--[[
FlyPaper
Functionality for sticking one frome to another frame
Methods:
FlyPaper.Stick(frame, otherFrame, tolerance, xOff, yOff) - Attempts to attach to
tolerance - how close the frames need to be to attach
xOff - how close, horizontally, the frames should be attached
yOff - how close, vertically, the frames should be attached
FlyPaper.StickToPoint(frame, otherFrame, point, xOff, yOff) - attempts to anchor to a specific point on
point - any non nil return value of FlyPaper.Stick;
Version History:
6.7.19:
Fixed a bug causing a frame to think it was still stuck to another frame when it really wasn't
Added FlyPaper.StickToPoint for reloading settings
--]]
local VERSION = "6.7.19";
if(FlyPaper and FlyPaper.version >= VERSION) then return; end
--returns true if , or one of the frames that is dependent on, is anchored to . Returns false otherwise.
local function FrameIsDependentOnFrame(frame, otherFrame)
if(not (otherFrame and frame) ) then
return false;
end
if(frame == otherFrame) then
return true;
end
local parent = frame.stuckTo;
while parent do
if(parent == otherFrame) then
return true;
end
parent = parent.stuckTo;
end
return false
end
--returns true if its actually possible to attach the two frames without error
local function CanAttach(frame, otherFrame)
if( not (frame and otherFrame) ) then
return false;
elseif(frame:GetNumPoints() == 0 or otherFrame:GetNumPoints() == 0 ) then
return false;
elseif(frame:GetWidth() == 0 or frame:GetHeight() == 0 or otherFrame:GetWidth() == 0 or otherFrame:GetHeight() == 0) then
return false;
elseif( FrameIsDependentOnFrame(otherFrame, frame) ) then
return false;
end
return true;
end
--[[ Attachment Functions ]]--
local function AttachToTop(frame, otherFrame, distLeft, distRight, distCenter, offset)
frame:ClearAllPoints();
--closest to the left
if(distLeft < distCenter and distLeft < distRight) then
frame:SetPoint("BOTTOMLEFT", otherFrame, "TOPLEFT", 0, offset);
return "TL";
--closest to the right
elseif(distRight < distCenter and distRight < distLeft ) then
frame:SetPoint("BOTTOMRIGHT", otherFrame, "TOPRIGHT", 0, offset);
return "TR";
--closest to the center
else
frame:SetPoint("BOTTOM", otherFrame, "TOP", 0, offset);
return "TC";
end
end
local function AttachToBottom(frame, otherFrame, distLeft, distRight, distCenter, offset)
frame:ClearAllPoints();
--bottomleft
if(distLeft < distCenter and distLeft < distRight) then
frame:SetPoint("TOPLEFT", otherFrame, "BOTTOMLEFT", 0, -offset);
return "BL";
--bottomright
elseif(distRight < distCenter and distRight < distLeft) then
frame:SetPoint("TOPRIGHT", otherFrame, "BOTTOMRIGHT", 0, -offset);
return "BR";
--bottom
else
frame:SetPoint("TOP", otherFrame, "BOTTOM", 0, -offset);
return "BC";
end
end
local function AttachToLeft(frame, otherFrame, distTop, distBottom, distCenter, offset)
frame:ClearAllPoints();
--bottomleft
if(distBottom < distTop and distBottom < distCenter) then
frame:SetPoint("BOTTOMRIGHT", otherFrame, "BOTTOMLEFT", -offset, 0);
return "LB";
--topleft
elseif(distTop < distBottom and distTop < distCenter) then
frame:SetPoint("TOPRIGHT", otherFrame, "TOPLEFT", -offset, 0);
return "LT";
--left
else
frame:SetPoint("RIGHT", otherFrame, "LEFT", -offset, 0);
return "LC";
end
end
local function AttachToRight(frame, otherFrame, distTop, distBottom, distCenter, offset)
frame:ClearAllPoints();
--bottomright
if(distBottom < distTop and distBottom < distCenter) then
frame:SetPoint("BOTTOMLEFT", otherFrame, "BOTTOMRIGHT", offset, 0);
return "RB";
--topright
elseif(distTop < distBottom and distTop < distCenter) then
frame:SetPoint("TOPLEFT", otherFrame, "TOPRIGHT", offset, 0);
return "RT";
--right
else
frame:SetPoint("LEFT", otherFrame, "RIGHT", offset, 0);
return "RC";
end
end
--[[ Usable Functions ]]--
FlyPaper = {
version = VERSION,
Stick = function(frame, otherFrame, tolerance, xOff, yOff)
if(not xOff) then
xOff = 0;
end
if(not yOff) then
yOff = 0;
end
if(not CanAttach(frame, otherFrame) ) then
if(frame) then
frame.stuckTo = nil;
end
return false;
end
--get anchoring points
local left = frame:GetLeft();
local right = frame:GetRight();
local top = frame:GetTop();
local bottom = frame:GetBottom();
local centerX, centerY = frame:GetCenter();
if(left and right and top and bottom and centerX) then
local oScale = otherFrame:GetScale();
left = left / oScale;
right = right / oScale;
top = top / oScale;
bottom = bottom /oScale;
centerX = centerX / oScale;
centerY = centerY / oScale;
else
frame.stuckTo = nil;
return false;
end
local oLeft = otherFrame:GetLeft();
local oRight = otherFrame:GetRight();
local oTop = otherFrame:GetTop();
local oBottom = otherFrame:GetBottom();
local oCenterX, oCenterY = otherFrame:GetCenter();
if(oLeft and oRight and oTop and oBottom and oCenterX) then
local scale = frame:GetScale();
oCenterX = oCenterX / scale;
oCenterY = oCenterY / scale;
oLeft = oLeft / scale;
oRight = oRight / scale;
oTop = oTop / scale;
oBottom = oBottom / scale;
else
frame.stuckTo = nil;
return false;
end
--[[ Start Attempting to Anchor to ]]--
if( (oLeft - tolerance <= left and oRight + tolerance >= right) or
(left - tolerance <= oLeft and right + tolerance >= oRight) ) then
local distCenter = math.abs(oCenterX - centerX);
local distLeft = math.abs(oLeft - left);
local distRight = math.abs(right - oRight);
--try to stick to the top if the distance is under the threshold distance to stick frames to each other (tolerance)
if( math.abs(oTop - bottom) <= tolerance ) then
local point = AttachToTop(frame, otherFrame, distLeft, distRight, distCenter, yOff);
frame.stuckTo = otherFrame;
return point;
--to the bottom
elseif( math.abs(oBottom - top) <= tolerance ) then
local point = AttachToBottom(frame, otherFrame, distLeft, distRight, distCenter, yOff);
frame.stuckTo = otherFrame;
return point;
end
end
if ( (oTop + tolerance >= top and oBottom - tolerance <= bottom) or
(top + tolerance >= oTop and bottom - tolerance <= oBottom) ) then
local distCenter = math.abs(oCenterY - centerY);
local distTop = math.abs(oTop - top);
local distBottom = math.abs(oBottom - bottom);
--to the left
if(math.abs(oLeft - right) <= tolerance ) then
local point = AttachToLeft(frame, otherFrame, distTop, distBottom, distCenter, xOff);
frame.stuckTo = otherFrame;
return point;
end
--to the right
if(math.abs(oRight - left) <= tolerance ) then
local point = AttachToRight(frame, otherFrame, distTop, distBottom, distCenter, xOff);
frame.stuckTo = otherFrame;
return point;
end
end
frame.stuckTo = nil;
return false;
end,
StickToPoint = function(frame, otherFrame, point, xOff, yOff)
if(not xOff) then
xOff = 0;
end
if(not yOff) then
yOff = 0;
end
--[[ Check to make sure we can anchor ]]--
--check to make sure its actually possible to attach the frames
if(not (point and CanAttach(frame, otherFrame)) ) then
if(frame) then
frame.stuckTo = nil;
end
return nil;
end
--check to make sure all anchoring points are valid
local left = frame:GetLeft();
local right = frame:GetRight();
local top = frame:GetTop();
local bottom = frame:GetBottom();
local centerX = frame:GetCenter();
if( not (left and right and top and bottom and centerX) ) then
frame.stuckTo = nil;
return nil;
end
local oLeft = otherFrame:GetLeft();
local oRight = otherFrame:GetRight();
local oTop = otherFrame:GetTop();
local oBottom = otherFrame:GetBottom();
local oCenterX = otherFrame:GetCenter();
if(not (oLeft and oRight and oTop and oBottom and oCenterX) ) then
frame.stuckTo = nil;
return nil;
end
--[[ Start Attempting to Anchor to ]]--
frame:ClearAllPoints();
if( point == "TL" ) then
frame:SetPoint("BOTTOMLEFT", otherFrame, "TOPLEFT", 0, yOff);
frame.stuckTo = otherFrame;
return point;
elseif(point == "TC") then
frame:SetPoint("BOTTOM", otherFrame, "TOP", 0, yOff);
frame.stuckTo = otherFrame;
return point;
elseif(point == "TR") then
frame:SetPoint("BOTTOMRIGHT", otherFrame, "TOPRIGHT", 0, yOff);
frame.stuckTo = otherFrame;
return point;
end
if( point == "BL" ) then
frame:SetPoint("TOPLEFT", otherFrame, "BOTTOMLEFT", 0, -yOff);
frame.stuckTo = otherFrame;
return point;
elseif(point == "BC") then
frame:SetPoint("TOP", otherFrame, "BOTTOM", 0, -yOff);
frame.stuckTo = otherFrame;
return point;
elseif(point == "BR") then
frame:SetPoint("TOPRIGHT", otherFrame, "BOTTOMRIGHT", 0, -yOff);
frame.stuckTo = otherFrame;
return point;
end
--to the left
if( point == "LB" ) then
frame:SetPoint("BOTTOMRIGHT", otherFrame, "BOTTOMLEFT", -xOff, 0);
frame.stuckTo = otherFrame;
return point;
elseif(point == "LC") then
frame:SetPoint("RIGHT", otherFrame, "LEFT", -xOff, 0);
frame.stuckTo = otherFrame;
return point;
elseif(point == "LT") then
frame:SetPoint("TOPRIGHT", otherFrame, "TOPLEFT", -xOff, 0);
frame.stuckTo = otherFrame;
return point;
end
--to the right
if( point == "RB" ) then
frame:SetPoint("BOTTOMLEFT", otherFrame, "BOTTOMRIGHT", xOff, 0);
frame.stuckTo = otherFrame;
return point;
elseif(point == "RC") then
frame:SetPoint("LEFT", otherFrame, "RIGHT", xOff, 0);
frame.stuckTo = otherFrame;
return point;
elseif(point == "RT") then
frame:SetPoint("TOPLEFT", otherFrame, "TOPRIGHT", xOff, 0);
frame.stuckTo = otherFrame;
return point;
end
frame.stuckTo = nil;
return nil;
end,
}