Quantcast

Fix arrow placement/saving/scaling

James Whitehead II [12-01-10 - 18:42]
Fix arrow placement/saving/scaling
Filename
TomTomLite.lua
TomTomLite.toc
Utils.lua
libs/LibWindow-1.1.lua
diff --git a/TomTomLite.lua b/TomTomLite.lua
index 580d179..e447dde 100644
--- a/TomTomLite.lua
+++ b/TomTomLite.lua
@@ -7,6 +7,7 @@ local L = addon.L

 addon.callbacks = LibStub("CallbackHandler-1.0"):New(addon)
 addon.mapdata = LibStub("LibMapData-1.0")
+addon.libwindow = LibStub("LibWindow-1.1")
 addon.waypoints = {}

 function addon:Initialize()
@@ -75,17 +76,11 @@ function addon:CreateCrazyArrow(name, parent)
         self.subtitle:SetFormattedText("%.1f yards", distance)
     end)

-    -- Code to handle moving the frame
-    frame:SetMovable(true)
-    frame:RegisterForDrag("LeftButton")
-    frame:SetScript("OnDragStart", frame.StartMoving)
-    frame:SetScript("OnDragStop", function(self)
-        self:SetUserPlaced(false)
-        self:StopMovingOrSizing()
-        addon:SavePosition(self)
-    end)
-    frame:SetScript("OnHide", frame:GetScript("OnDragStop"))
-    self:RestorePosition(frame)
+    self.libwindow.RegisterConfig(frame, self.db.profile.positions)
+    self.libwindow.RestorePosition(frame)
+    self.libwindow.MakeDraggable(frame)
+    self.libwindow.EnableMouseOnAlt(frame)
+    self.libwindow.EnableMouseWheelScaling(frame)

     return frame
 end
diff --git a/TomTomLite.toc b/TomTomLite.toc
index 0a9ff12..345167b 100755
--- a/TomTomLite.toc
+++ b/TomTomLite.toc
@@ -15,6 +15,7 @@ libs\LibStub\LibStub.lua
 libs\CallbackHandler-1.0\CallbackHandler-1.0.xml
 libs\AceDB-3.0\AceDB-3.0.xml
 libs\LibMapData-1.0\library.lua
+libs\LibWindow-1.1.lua

 Utils.lua
 DatabaseDefaults.lua
diff --git a/Utils.lua b/Utils.lua
index 44179cc..d3b5bfa 100644
--- a/Utils.lua
+++ b/Utils.lua
@@ -24,44 +24,3 @@ function addon:ColorGradient(perc, ...)
         b1 + (b2-b1)*relperc
     end
 end
-
-function addon:SavePosition(f)
-    local name = f:GetName()
-    local x,y = f:GetLeft(), f:GetTop()
-    local s = f:GetEffectiveScale()
-
-    x,y = x*s,y*s
-
-    local opt = addon.db.profile.positions[name]
-    if not opt then
-        addon.db.profile.positions[name] = {}
-        opt = addon.db.profile.positions[name]
-    end
-    opt.PosX = x
-    opt.PosY = y
-end
-
-function addon:RestorePosition(f)
-    local name = f:GetName()
-    local opt = addon.db.profile.positions[name]
-    if not opt then
-        addon.db.profile.positions[name] = {}
-        opt = addon.db.profile.positions[name]
-    end
-
-    local x = opt.PosX
-    local y = opt.PosY
-
-    local s = f:GetEffectiveScale()
-
-    if not x or not y then
-        f:ClearAllPoints()
-        f:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
-        return
-    end
-
-    x,y = x/s,y/s
-
-    f:ClearAllPoints()
-    f:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
-end
diff --git a/libs/LibWindow-1.1.lua b/libs/LibWindow-1.1.lua
new file mode 100644
index 0000000..fdc4683
--- /dev/null
+++ b/libs/LibWindow-1.1.lua
@@ -0,0 +1,312 @@
+--[[
+Name: LibWindow-1.1
+Revision: $Rev: 3 $
+Author(s): Mikk (dpsgnome@mail.com)
+Website: http://old.wowace.com/wiki/LibWindow-1.1
+Documentation: http://old.wowace.com/wiki/LibWindow-1.1
+SVN: http://svn.wowace.com/root/trunk/WindowLib/Window-1.0
+Description: A library that handles the basics of "window" style frames: scaling, smart position saving, dragging..
+Dependencies: none
+License: Public Domain
+]]
+
+local MAJOR = "LibWindow-1.1"
+local MINOR = tonumber(("$Revision: 3 $"):match("(%d+)"))
+
+local lib = LibStub:NewLibrary(MAJOR,MINOR)
+if not lib then return end
+
+local function print(msg) ChatFrame1:AddMessage(MAJOR..": "..tostring(msg)) end
+
+
+lib.utilFrame = lib.utilFrame or CreateFrame("Frame")
+lib.delayedSavePosition = lib.delayedSavePosition or {}
+lib.windowData = lib.windowData or {}
+  --[frameref]={
+  --  names={optional names data from .RegisterConfig()}
+  --  storage= -- tableref where config data is read/written
+  --  altEnable=true/false
+  --}
+
+
+lib.embeds = lib.embeds or {}
+
+local mixins = {} -- "FuncName"=true
+
+
+
+---------------------------------------------------------
+-- UTILITIES
+---------------------------------------------------------
+
+
+local function getStorageName(frame, name)
+  local names = lib.windowData[frame].names
+  if names then
+		if names[name] then
+			return names[name]
+		end
+		if names.prefix then
+			return names.prefix .. name;
+		end
+	end
+	return name;
+end
+
+local function setStorage(frame, name, value)
+	lib.windowData[frame].storage[getStorageName(frame, name)] = value
+end
+
+local function getStorage(frame, name)
+	return lib.windowData[frame].storage[getStorageName(frame, name)]
+end
+
+
+lib.utilFrame:SetScript("OnUpdate", function(this)
+	this:Hide()
+	for frame,_ in pairs(lib.delayedSavePosition) do
+		lib.delayedSavePosition[frame] = nil
+		lib.SavePosition(frame)
+	end
+end)
+
+local function queueSavePosition(frame)
+	lib.delayedSavePosition[frame] = true
+	lib.utilFrame:Show()
+end
+
+
+
+---------------------------------------------------------
+-- IMPORTANT APIS
+---------------------------------------------------------
+
+mixins["RegisterConfig"]=true
+function lib.RegisterConfig(frame, storage, names)
+	if not lib.windowData[frame] then
+		lib.windowData[frame] = {}
+	end
+	lib.windowData[frame].names = names
+	lib.windowData[frame].storage = storage
+
+	--[[ debug
+	frame.tx = frame:CreateTexture()
+	frame.tx:SetTexture(0,0,0, 0.4)
+	frame.tx:SetAllPoints(frame)
+	frame.tx:Show()
+	]]
+end
+
+
+
+
+---------------------------------------------------------
+-- POSITIONING AND SCALING
+---------------------------------------------------------
+
+local nilParent = {
+	GetWidth = function()
+		return GetScreenWidth() * UIParent:GetScale()
+	end,
+	GetHeight = function()
+		return GetScreenHeight() * UIParent:GetScale()
+	end,
+	GetScale = function()
+		return 1
+	end,
+}
+
+mixins["SavePosition"]=true
+function lib.SavePosition(frame)
+	local parent = frame:GetParent() or nilParent
+	-- No, this won't work very well with frames that aren't parented to nil or UIParent
+	local s = frame:GetScale()
+	local left,top = frame:GetLeft()*s, frame:GetTop()*s
+	local right,bottom = frame:GetRight()*s, frame:GetBottom()*s
+	local pwidth, pheight = parent:GetWidth(), parent:GetHeight()
+
+	local x,y,point;
+	if left < (pwidth-right) and left < abs((left+right)/2 - pwidth/2) then
+		x = left;
+		point="LEFT";
+	elseif (pwidth-right) < abs((left+right)/2 - pwidth/2) then
+		x = right-pwidth;
+		point="RIGHT";
+	else
+		x = (left+right)/2 - pwidth/2;
+		point="";
+	end
+
+	if bottom < (pheight-top) and bottom < abs((bottom+top)/2 - pheight/2) then
+		y = bottom;
+		point="BOTTOM"..point;
+	elseif (pheight-top) < abs((bottom+top)/2 - pheight/2) then
+		y = top-pheight;
+		point="TOP"..point;
+	else
+		y = (bottom+top)/2 - pheight/2;
+		-- point=""..point;
+	end
+
+	if point=="" then
+		point = "CENTER"
+	end
+
+	setStorage(frame, "x", x)
+	setStorage(frame, "y", y)
+	setStorage(frame, "point", point)
+	setStorage(frame, "scale", s)
+
+	frame:ClearAllPoints()
+	frame:SetPoint(point, frame:GetParent(), point, x/s, y/s);
+end
+
+
+mixins["RestorePosition"]=true
+function lib.RestorePosition(frame)
+	local x = getStorage(frame, "x")
+	local y = getStorage(frame, "y")
+	local point = getStorage(frame, "point")
+
+	local s = getStorage(frame, "scale")
+	if s then
+		frame:SetScale(s)
+	else
+		s = frame:GetScale()
+	end
+
+	if not x or not y then		-- nothing stored in config yet, smack it in the center
+		x=0; y=0; point="CENTER"
+	end
+
+	x = x/s
+	y = y/s
+
+	frame:ClearAllPoints()
+	if not point and y==0 then	-- errr why did i do this check again? must have been a reason, but i can't remember it =/
+		point="CENTER"
+	end
+
+	if not point then	-- we have position, but no point, which probably means we're going from data stored by the addon itself before LibWindow was added to it. It was PROBABLY topleft->bottomleft anchored. Most do it that way.
+		frame:SetPoint("TOPLEFT", frame:GetParent(), "BOTTOMLEFT", x, y)
+		-- make it compute a better attachpoint (on next update)
+		queueSavePosition(frame)
+		return
+	end
+
+	frame:SetPoint(point, frame:GetParent(), point, x, y)
+end
+
+
+mixins["SetScale"]=true
+function lib.SetScale(frame, scale)
+	setStorage(frame, "scale", scale)
+	frame:SetScale(scale)
+	lib.RestorePosition(frame)
+end
+
+
+
+---------------------------------------------------------
+-- DRAG SUPPORT
+---------------------------------------------------------
+
+
+function lib.OnDragStart(frame)
+	lib.windowData[frame].isDragging = true
+	frame:StartMoving()
+end
+
+
+function lib.OnDragStop(frame)
+	frame:StopMovingOrSizing()
+	lib.SavePosition(frame)
+	lib.windowData[frame].isDragging = false
+	if lib.windowData[frame].altEnable and not IsAltKeyDown() then
+		frame:EnableMouse(false)
+	end
+end
+
+local function onDragStart(...) return lib.OnDragStart(...) end  -- upgradable
+local function onDragStop(...) return lib.OnDragStop(...) end  -- upgradable
+
+mixins["MakeDraggable"]=true
+function lib.MakeDraggable(frame)
+	assert(lib.windowData[frame])
+	frame:SetMovable(true)
+	frame:SetScript("OnDragStart", onDragStart)
+	frame:SetScript("OnDragStop", onDragStop)
+	frame:RegisterForDrag("LeftButton")
+end
+
+
+---------------------------------------------------------
+-- MOUSEWHEEL
+---------------------------------------------------------
+
+function lib.OnMouseWheel(frame, dir)
+	local scale = getStorage(frame, "scale")
+	if dir<0 then
+		scale=max(scale*0.9, 0.1)
+	else
+		scale=min(scale/0.9, 3)
+	end
+	lib.SetScale(frame, scale)
+end
+
+local function onMouseWheel(...) return lib.OnMouseWheel(...) end  -- upgradable
+
+mixins["EnableMouseWheelScaling"]=true
+function lib.EnableMouseWheelScaling(frame)
+	frame:SetScript("OnMouseWheel", onMouseWheel)
+end
+
+
+---------------------------------------------------------
+-- ENABLEMOUSE-ON-ALT
+---------------------------------------------------------
+
+lib.utilFrame:SetScript("OnEvent", function(this, event, key, state)
+	if event=="MODIFIER_STATE_CHANGED" then
+		if key == "LALT" or key == "RALT" then
+			for frame,_ in pairs(lib.altEnabledFrames) do
+				if not lib.windowData[frame].isDragging then		-- if it's already dragging, it'll disable mouse on DragStop instead
+					frame:EnableMouse(state == 1)
+				end
+			end
+		end
+	end
+end)
+
+mixins["MakeDraggable"]=true
+function lib.EnableMouseOnAlt(frame)
+	assert(lib.windowData[frame])
+	lib.windowData[frame].altEnable = true
+	frame:EnableMouse(not not IsAltKeyDown())
+	if not lib.altEnabledFrames then
+		lib.altEnabledFrames = {}
+		lib.utilFrame:RegisterEvent("MODIFIER_STATE_CHANGED")
+	end
+	lib.altEnabledFrames[frame] = true
+end
+
+
+
+---------------------------------------------------------
+-- Embed support (into FRAMES, not addons!)
+---------------------------------------------------------
+
+function lib:Embed(target)
+	if not target or not target[0] or not target.GetFrameType then
+		error("Usage: LibWindow:Embed(frame)", 1)
+	end
+	for name, _ in pairs(mixins) do
+		target[name] = self[name]
+	end
+	lib.embeds[target] = true
+	return target
+end
+
+for target, _ in pairs(lib.embeds) do
+	lib:Embed(target)
+end