You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
318 lines
8.5 KiB
318 lines
8.5 KiB
--[[
|
|
Name: LibWindow-1.1
|
|
Revision: $Rev: 18 $
|
|
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: 18 $"):match("(%d+)"))
|
|
|
|
local lib = LibStub:NewLibrary(MAJOR,MINOR)
|
|
if not lib then return end
|
|
|
|
local min,max,abs = min,max,abs
|
|
local pairs = pairs
|
|
local tostring = tostring
|
|
local UIParent,GetScreenWidth,GetScreenHeight,IsAltKeyDown = UIParent,GetScreenWidth,GetScreenHeight,IsAltKeyDown
|
|
-- GLOBALS: error, ChatFrame1, assert
|
|
|
|
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()
|
|
if not s then return end
|
|
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.lw11origSetScale or frame.SetScale)(frame,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.lw11origSetScale or frame.SetScale)(frame,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["EnableMouseOnAlt"]=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.GetObjectType then
|
|
error("Usage: LibWindow:Embed(frame)", 1)
|
|
end
|
|
target.lw11origSetScale = target.SetScale
|
|
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
|
|
|