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.

263 lines
7.7 KiB

-- Neuron is a World of Warcraft® user interface addon.
-- Copyright (c) 2017-2021 Britt W. Yazel
-- Copyright (c) 2006-2014 Connor H. Chenoweth
-- This code is licensed under the MIT license (see LICENSE for details)
local _, addonTable = ...
local Neuron = addonTable.Neuron
local Bar = Neuron.Bar
local function frameIsDependentOnFrame(frame, otherFrame)
if frame and otherFrame then
if frame == otherFrame then return true end
local points = frame:GetNumPoints()
for i=1,points do
local parent = select(2, frame:GetPoint(i))
if frameIsDependentOnFrame(parent, otherFrame) then return true end
end
end
end
local function canAttach(frame, otherFrame)
if not frame and otherFrame then
return
elseif frame:GetNumPoints() == 0 or otherFrame:GetNumPoints() == 0 then
return
elseif frame:GetWidth() == 0 or frame:GetHeight() == 0 or otherFrame:GetWidth() == 0 or otherFrame:GetHeight() == 0 then
return
elseif frameIsDependentOnFrame(otherFrame, frame) then
return
end
return true
end
--[[ Attachment Functions ]]--
local function attachToTop(frame, otherFrame, distLeft, distRight, distCenter, offset)
frame:ClearAllPoints()
if distLeft < distCenter and distLeft < distRight then
frame:SetPoint("BOTTOMLEFT", otherFrame, "TOPLEFT", 0, offset); return "TL"
elseif distRight < distCenter and distRight < distLeft then
frame:SetPoint("BOTTOMRIGHT", otherFrame, "TOPRIGHT", 0, offset); return "TR"
else
frame:SetPoint("BOTTOM", otherFrame, "TOP", 0, offset); return "TC"
end
end
local function attachToBottom(frame, otherFrame, distLeft, distRight, distCenter, offset)
frame:ClearAllPoints()
if distLeft < distCenter and distLeft < distRight then
frame:SetPoint("TOPLEFT", otherFrame, "BOTTOMLEFT", 0, -offset); return "BL"
elseif distRight < distCenter and distRight < distLeft then
frame:SetPoint("TOPRIGHT", otherFrame, "BOTTOMRIGHT", 0, -offset); return "BR"
else
frame:SetPoint("TOP", otherFrame, "BOTTOM", 0, -offset); return "BC"
end
end
local function attachToLeft(frame, otherFrame, distTop, distBottom, distCenter, offset)
frame:ClearAllPoints()
if distBottom < distTop and distBottom < distCenter then
frame:SetPoint("BOTTOMRIGHT", otherFrame, "BOTTOMLEFT", -offset, 0); return "LB"
elseif distTop < distBottom and distTop < distCenter then
frame:SetPoint("TOPRIGHT", otherFrame, "TOPLEFT", -offset, 0); return "LT"
else
frame:SetPoint("RIGHT", otherFrame, "LEFT", -offset, 0); return "LC"
end
end
local function attachToRight(frame, otherFrame, distTop, distBottom, distCenter, offset)
frame:ClearAllPoints()
if distBottom < distTop and distBottom < distCenter then
frame:SetPoint("BOTTOMLEFT", otherFrame, "BOTTOMRIGHT", offset, 0); return "RB"
elseif distTop < distBottom and distTop < distCenter then
frame:SetPoint("TOPLEFT", otherFrame, "TOPRIGHT", offset, 0); return "RT"
else
frame:SetPoint("LEFT", otherFrame, "RIGHT", offset, 0); return "RC"
end
end
local function attachToCenter(frame, otherFrame)
frame:ClearAllPoints()
frame:SetPoint("CENTER", otherFrame, "CENTER", 0, 0); return "CT"
end
--[[ Usable Functions ]]--
function Bar:StickToEdge()
local point, x, y= self:GetPosition()
local changed
local w, h, rTol = self:GetWidth()/2, self:GetHeight()/2, Neuron.SNAPTO_TOLERANCE
local function calcX(opt)
if opt == 1 then if x <= w+rTol then x = w; changed = true end
elseif opt == 2 then if x >= -(w+rTol) then x = -(w); changed = true end
elseif opt == 3 then if math.abs(x) <= rTol then x = 0; changed = true end
end
end
local function calcY(opt)
if opt == 1 then if y <= h+rTol then y = h; changed = true end
elseif opt == 2 then if y >= -(h+rTol) then y = -(h); changed = true end
elseif opt == 3 then if math.abs(y) <= rTol then y = 0; changed = true end
end
end
if point == "CENTER" then calcX(3); calcY(3) end
if point:find("LEFT") then calcX(1); calcY(3) end
if point:find("RIGHT") then calcX(2); calcY(3) end
if not changed and point:find("BOTTOM") then calcX(3); calcY(1) end
if not changed and point:find("TOP") then calcX(3); calcY(2) end
if changed then
self.data.point = point; self:SetXAxis(x); self:SetYAxis(y)
self:SetPosition()
end
end
function Bar:Stick(oFrame, tolerance, xOff, yOff)
xOff, yOff = xOff or 0, yOff or 0
if not canAttach(self, oFrame) then return end
local left, right, top, bottom = self:GetLeft(), self:GetRight(), self:GetTop(), self:GetBottom()
local centerX, centerY = self:GetCenter()
if left and right and top and bottom and centerX then
local oScale = oFrame:GetScale()
left = left/oScale; right = right/oScale; top = top/oScale; bottom = bottom/oScale
centerX = centerX/oScale; centerY = centerY/oScale
else return end
local oLeft, oRight, oTop, oBottom = oFrame:GetLeft(), oFrame:GetRight(), oFrame:GetTop(), oFrame:GetBottom()
local oCenterX, oCenterY = oFrame:GetCenter()
if oLeft and oRight and oTop and oBottom and oCenterX then
local scale = self:GetScale()
oLeft = oLeft/scale; oRight = oRight/scale; oTop = oTop/scale; oBottom = oBottom/scale
oCenterX = oCenterX/scale; oCenterY = oCenterY/scale
else return end
if (oLeft - tolerance <= left and oRight + tolerance >= right) or (left - tolerance <= oLeft and right + tolerance >= oRight) then
local distCenter, distLeft, distRight = math.abs(oCenterX - centerX), math.abs(oLeft - left), math.abs(right - oRight)
if math.abs(oTop - bottom) <= tolerance then
return attachToTop(self, oFrame, distLeft, distRight, distCenter, yOff)
elseif math.abs(oBottom - top) <= tolerance then
return attachToBottom(self, oFrame, distLeft, distRight, distCenter, yOff)
end
end
if (oTop + tolerance >= top and oBottom - tolerance <= bottom) or (top + tolerance >= oTop and bottom - tolerance <= oBottom) then
local distCenter, distTop, distBottom = math.abs(oCenterY - centerY), math.abs(oTop - top), math.abs(oBottom - bottom)
if math.abs(oLeft - right) <= tolerance then
return attachToLeft(self, oFrame, distTop, distBottom, distCenter, xOff)
end
if math.abs(oRight - left) <= tolerance then
return attachToRight(self, oFrame, distTop, distBottom, distCenter, xOff)
end
end
if oCenterX > centerX - tolerance/2 and oCenterX < centerX + tolerance/2 and oCenterY > centerY - tolerance/2 and oCenterY < centerY + tolerance/2 then
return attachToCenter(self, oFrame)
end
end
function Bar:StickToPoint(oFrame, point, xOff, yOff)
xOff, yOff = xOff or 0, yOff or 0
if not (point and canAttach(self, oFrame)) then return end
self:ClearAllPoints()
if point == "TL" then
self:SetPoint("BOTTOMLEFT", oFrame, "TOPLEFT", 0, yOff); return point
elseif point == "TC" then
self:SetPoint("BOTTOM", oFrame, "TOP", 0, yOff); return point
elseif point == "TR" then
self:SetPoint("BOTTOMRIGHT", oFrame, "TOPRIGHT", 0, yOff); return point
end
if point == "BL" then
self:SetPoint("TOPLEFT", oFrame, "BOTTOMLEFT", 0, -yOff); return point
elseif point == "BC" then
self:SetPoint("TOP", oFrame, "BOTTOM", 0, -yOff); return point
elseif point == "BR" then
self:SetPoint("TOPRIGHT", oFrame, "BOTTOMRIGHT", 0, -yOff); return point
end
if point == "LB" then
self:SetPoint("BOTTOMRIGHT", oFrame, "BOTTOMLEFT", -xOff, 0); return point
elseif point == "LC" then
self:SetPoint("RIGHT", oFrame, "LEFT", -xOff, 0); return point
elseif point == "LT" then
self:SetPoint("TOPRIGHT", oFrame, "TOPLEFT", -xOff, 0); return point
end
if point == "RB" then
self:SetPoint("BOTTOMLEFT", oFrame, "BOTTOMRIGHT", xOff, 0); return point
elseif point == "RC" then
self:SetPoint("LEFT", oFrame, "RIGHT", xOff, 0); return point
elseif point == "RT" then
self:SetPoint("TOPLEFT", oFrame, "TOPRIGHT", xOff, 0); return point
end
if point == "CT" then
self:SetPoint("CENTER", oFrame, "CENTER", 0, 0); return point
end
end