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