Tercioo@9: --[[ Tercioo@9: Name: LibWindow-1.1 Tercioo@9: Revision: $Rev: 8 $ Tercioo@9: Author(s): Mikk (dpsgnome@mail.com) Tercioo@9: Website: http://old.wowace.com/wiki/LibWindow-1.1 Tercioo@9: Documentation: http://old.wowace.com/wiki/LibWindow-1.1 Tercioo@9: SVN: http://svn.wowace.com/root/trunk/WindowLib/Window-1.0 Tercioo@9: Description: A library that handles the basics of "window" style frames: scaling, smart position saving, dragging.. Tercioo@9: Dependencies: none Tercioo@9: License: Public Domain Tercioo@9: ]] Tercioo@9: Tercioo@9: local MAJOR = "LibWindow-1.1" Tercioo@9: local MINOR = tonumber(("$Revision: 8 $"):match("(%d+)")) Tercioo@9: Tercioo@9: local lib = LibStub:NewLibrary(MAJOR,MINOR) Tercioo@9: if not lib then return end Tercioo@9: Tercioo@9: local min,max,abs = min,max,abs Tercioo@9: local pairs = pairs Tercioo@9: local tostring = tostring Tercioo@9: local UIParent,GetScreenWidth,GetScreenHeight,IsAltKeyDown = UIParent,GetScreenWidth,GetScreenHeight,IsAltKeyDown Tercioo@9: -- GLOBALS: error, ChatFrame1, assert Tercioo@9: Tercioo@9: local function print(msg) ChatFrame1:AddMessage(MAJOR..": "..tostring(msg)) end Tercioo@9: Tercioo@9: lib.utilFrame = lib.utilFrame or CreateFrame("Frame") Tercioo@9: lib.delayedSavePosition = lib.delayedSavePosition or {} Tercioo@9: lib.windowData = lib.windowData or {} Tercioo@9: --[frameref]={ Tercioo@9: -- names={optional names data from .RegisterConfig()} Tercioo@9: -- storage= -- tableref where config data is read/written Tercioo@9: -- altEnable=true/false Tercioo@9: --} Tercioo@9: Tercioo@9: Tercioo@9: lib.embeds = lib.embeds or {} Tercioo@9: Tercioo@9: local mixins = {} -- "FuncName"=true Tercioo@9: Tercioo@9: Tercioo@9: Tercioo@9: --------------------------------------------------------- Tercioo@9: -- UTILITIES Tercioo@9: --------------------------------------------------------- Tercioo@9: Tercioo@9: Tercioo@9: local function getStorageName(frame, name) Tercioo@9: local names = lib.windowData[frame].names Tercioo@9: if names then Tercioo@9: if names[name] then Tercioo@9: return names[name] Tercioo@9: end Tercioo@9: if names.prefix then Tercioo@9: return names.prefix .. name; Tercioo@9: end Tercioo@9: end Tercioo@9: return name; Tercioo@9: end Tercioo@9: Tercioo@9: local function setStorage(frame, name, value) Tercioo@9: lib.windowData[frame].storage[getStorageName(frame, name)] = value Tercioo@9: end Tercioo@9: Tercioo@9: local function getStorage(frame, name) Tercioo@9: return lib.windowData[frame].storage[getStorageName(frame, name)] Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: lib.utilFrame:SetScript("OnUpdate", function(this) Tercioo@9: this:Hide() Tercioo@9: for frame,_ in pairs(lib.delayedSavePosition) do Tercioo@9: lib.delayedSavePosition[frame] = nil Tercioo@9: lib.SavePosition(frame) Tercioo@9: end Tercioo@9: end) Tercioo@9: Tercioo@9: local function queueSavePosition(frame) Tercioo@9: lib.delayedSavePosition[frame] = true Tercioo@9: lib.utilFrame:Show() Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: --------------------------------------------------------- Tercioo@9: -- IMPORTANT APIS Tercioo@9: --------------------------------------------------------- Tercioo@9: Tercioo@9: mixins["RegisterConfig"]=true Tercioo@9: function lib.RegisterConfig(frame, storage, names) Tercioo@9: if not lib.windowData[frame] then Tercioo@9: lib.windowData[frame] = {} Tercioo@9: end Tercioo@9: lib.windowData[frame].names = names Tercioo@9: lib.windowData[frame].storage = storage Tercioo@9: Tercioo@9: --[[ debug Tercioo@9: frame.tx = frame:CreateTexture() Tercioo@9: frame.tx:SetTexture(0,0,0, 0.4) Tercioo@9: frame.tx:SetAllPoints(frame) Tercioo@9: frame.tx:Show() Tercioo@9: ]] Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: Tercioo@9: Tercioo@9: --------------------------------------------------------- Tercioo@9: -- POSITIONING AND SCALING Tercioo@9: --------------------------------------------------------- Tercioo@9: Tercioo@9: local nilParent = { Tercioo@9: GetWidth = function() Tercioo@9: return GetScreenWidth() * UIParent:GetScale() Tercioo@9: end, Tercioo@9: GetHeight = function() Tercioo@9: return GetScreenHeight() * UIParent:GetScale() Tercioo@9: end, Tercioo@9: GetScale = function() Tercioo@9: return 1 Tercioo@9: end, Tercioo@9: } Tercioo@9: Tercioo@9: mixins["SavePosition"]=true Tercioo@9: function lib.SavePosition(frame) Tercioo@9: local parent = frame:GetParent() or nilParent Tercioo@9: -- No, this won't work very well with frames that aren't parented to nil or UIParent Tercioo@9: local s = frame:GetScale() Tercioo@9: local left,top = frame:GetLeft()*s, frame:GetTop()*s Tercioo@9: local right,bottom = frame:GetRight()*s, frame:GetBottom()*s Tercioo@9: local pwidth, pheight = parent:GetWidth(), parent:GetHeight() Tercioo@9: Tercioo@9: local x,y,point; Tercioo@9: if left < (pwidth-right) and left < abs((left+right)/2 - pwidth/2) then Tercioo@9: x = left; Tercioo@9: point="LEFT"; Tercioo@9: elseif (pwidth-right) < abs((left+right)/2 - pwidth/2) then Tercioo@9: x = right-pwidth; Tercioo@9: point="RIGHT"; Tercioo@9: else Tercioo@9: x = (left+right)/2 - pwidth/2; Tercioo@9: point=""; Tercioo@9: end Tercioo@9: Tercioo@9: if bottom < (pheight-top) and bottom < abs((bottom+top)/2 - pheight/2) then Tercioo@9: y = bottom; Tercioo@9: point="BOTTOM"..point; Tercioo@9: elseif (pheight-top) < abs((bottom+top)/2 - pheight/2) then Tercioo@9: y = top-pheight; Tercioo@9: point="TOP"..point; Tercioo@9: else Tercioo@9: y = (bottom+top)/2 - pheight/2; Tercioo@9: -- point=""..point; Tercioo@9: end Tercioo@9: Tercioo@9: if point=="" then Tercioo@9: point = "CENTER" Tercioo@9: end Tercioo@9: Tercioo@9: setStorage(frame, "x", x) Tercioo@9: setStorage(frame, "y", y) Tercioo@9: setStorage(frame, "point", point) Tercioo@9: setStorage(frame, "scale", s) Tercioo@9: Tercioo@9: frame:ClearAllPoints() Tercioo@9: frame:SetPoint(point, frame:GetParent(), point, x/s, y/s); Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: mixins["RestorePosition"]=true Tercioo@9: function lib.RestorePosition(frame) Tercioo@9: local x = getStorage(frame, "x") Tercioo@9: local y = getStorage(frame, "y") Tercioo@9: local point = getStorage(frame, "point") Tercioo@9: Tercioo@9: local s = getStorage(frame, "scale") Tercioo@9: if s then Tercioo@9: (frame.lw11origSetScale or frame.SetScale)(frame,s) Tercioo@9: else Tercioo@9: s = frame:GetScale() Tercioo@9: end Tercioo@9: Tercioo@9: if not x or not y then -- nothing stored in config yet, smack it in the center Tercioo@9: x=0; y=0; point="CENTER" Tercioo@9: end Tercioo@9: Tercioo@9: x = x/s Tercioo@9: y = y/s Tercioo@9: Tercioo@9: frame:ClearAllPoints() Tercioo@9: 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 =/ Tercioo@9: point="CENTER" Tercioo@9: end Tercioo@9: Tercioo@9: 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. Tercioo@9: frame:SetPoint("TOPLEFT", frame:GetParent(), "BOTTOMLEFT", x, y) Tercioo@9: -- make it compute a better attachpoint (on next update) Tercioo@9: queueSavePosition(frame) Tercioo@9: return Tercioo@9: end Tercioo@9: Tercioo@9: frame:SetPoint(point, frame:GetParent(), point, x, y) Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: mixins["SetScale"]=true Tercioo@9: function lib.SetScale(frame, scale) Tercioo@9: setStorage(frame, "scale", scale); Tercioo@9: (frame.lw11origSetScale or frame.SetScale)(frame,scale) Tercioo@9: lib.RestorePosition(frame) Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: Tercioo@9: --------------------------------------------------------- Tercioo@9: -- DRAG SUPPORT Tercioo@9: --------------------------------------------------------- Tercioo@9: Tercioo@9: Tercioo@9: function lib.OnDragStart(frame) Tercioo@9: lib.windowData[frame].isDragging = true Tercioo@9: frame:StartMoving() Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: function lib.OnDragStop(frame) Tercioo@9: frame:StopMovingOrSizing() Tercioo@9: lib.SavePosition(frame) Tercioo@9: lib.windowData[frame].isDragging = false Tercioo@9: if lib.windowData[frame].altEnable and not IsAltKeyDown() then Tercioo@9: frame:EnableMouse(false) Tercioo@9: end Tercioo@9: end Tercioo@9: Tercioo@9: local function onDragStart(...) return lib.OnDragStart(...) end -- upgradable Tercioo@9: local function onDragStop(...) return lib.OnDragStop(...) end -- upgradable Tercioo@9: Tercioo@9: mixins["MakeDraggable"]=true Tercioo@9: function lib.MakeDraggable(frame) Tercioo@9: assert(lib.windowData[frame]) Tercioo@9: frame:SetMovable(true) Tercioo@9: frame:SetScript("OnDragStart", onDragStart) Tercioo@9: frame:SetScript("OnDragStop", onDragStop) Tercioo@9: frame:RegisterForDrag("LeftButton") Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: --------------------------------------------------------- Tercioo@9: -- MOUSEWHEEL Tercioo@9: --------------------------------------------------------- Tercioo@9: Tercioo@9: function lib.OnMouseWheel(frame, dir) Tercioo@9: local scale = getStorage(frame, "scale") Tercioo@9: if dir<0 then Tercioo@9: scale=max(scale*0.9, 0.1) Tercioo@9: else Tercioo@9: scale=min(scale/0.9, 3) Tercioo@9: end Tercioo@9: lib.SetScale(frame, scale) Tercioo@9: end Tercioo@9: Tercioo@9: local function onMouseWheel(...) return lib.OnMouseWheel(...) end -- upgradable Tercioo@9: Tercioo@9: mixins["EnableMouseWheelScaling"]=true Tercioo@9: function lib.EnableMouseWheelScaling(frame) Tercioo@9: frame:SetScript("OnMouseWheel", onMouseWheel) Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: --------------------------------------------------------- Tercioo@9: -- ENABLEMOUSE-ON-ALT Tercioo@9: --------------------------------------------------------- Tercioo@9: Tercioo@9: lib.utilFrame:SetScript("OnEvent", function(this, event, key, state) Tercioo@9: if event=="MODIFIER_STATE_CHANGED" then Tercioo@9: if key == "LALT" or key == "RALT" then Tercioo@9: for frame,_ in pairs(lib.altEnabledFrames) do Tercioo@9: if not lib.windowData[frame].isDragging then -- if it's already dragging, it'll disable mouse on DragStop instead Tercioo@9: frame:EnableMouse(state == 1) Tercioo@9: end Tercioo@9: end Tercioo@9: end Tercioo@9: end Tercioo@9: end) Tercioo@9: Tercioo@9: mixins["EnableMouseOnAlt"]=true Tercioo@9: function lib.EnableMouseOnAlt(frame) Tercioo@9: assert(lib.windowData[frame]) Tercioo@9: lib.windowData[frame].altEnable = true Tercioo@9: frame:EnableMouse(not not IsAltKeyDown()) Tercioo@9: if not lib.altEnabledFrames then Tercioo@9: lib.altEnabledFrames = {} Tercioo@9: lib.utilFrame:RegisterEvent("MODIFIER_STATE_CHANGED") Tercioo@9: end Tercioo@9: lib.altEnabledFrames[frame] = true Tercioo@9: end Tercioo@9: Tercioo@9: Tercioo@9: Tercioo@9: --------------------------------------------------------- Tercioo@9: -- Embed support (into FRAMES, not addons!) Tercioo@9: --------------------------------------------------------- Tercioo@9: Tercioo@9: function lib:Embed(target) Tercioo@9: if not target or not target[0] or not target.GetObjectType then Tercioo@9: error("Usage: LibWindow:Embed(frame)", 1) Tercioo@9: end Tercioo@9: target.lw11origSetScale = target.SetScale Tercioo@9: for name, _ in pairs(mixins) do Tercioo@9: target[name] = self[name] Tercioo@9: end Tercioo@9: lib.embeds[target] = true Tercioo@9: return target Tercioo@9: end Tercioo@9: Tercioo@9: for target, _ in pairs(lib.embeds) do Tercioo@9: lib:Embed(target) Tercioo@9: end