vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
--[[
        FlyPaper
                Functionality for sticking one frome to another frame
                
        Methods:
                FlyPaper.Stick(frame, otherFrame, tolerance, xOff, yOff) - Attempts to attach <frame> to <otherFrame>
                        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 <frame> to a specific point on <otherFrame>
                        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 <frame>, or one of the frames that <frame> is dependent on, is anchored to <otherFrame>.  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 <frame> to <otherFrame> ]]--
                
                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 <frame> to <otherFrame> ]]--
                
                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,
}

Generated by GNU Enscript 1.6.5.90.