math.round = function(self)
return math.floor(self + 0.5)
end
local function GetRelativePoint(points, frame)
if not points then
points = {"BOTTOMLEFT", UIParent, "BOTTOMLEFT"}
end
local rel = points[2]
if not rel then
rel = UIParent
end
if type(rel) == "string" then
rel = _G[rel]
end
if not rel then
return
end
local point = string.upper(points[1])
local relPoint = string.upper(points[3])
local rX, rY, pX, pY
if rel:GetLeft() then
if relPoint == "TOPRIGHT" then
rY = rel:GetTop()
rX = rel:GetRight()
elseif relPoint == "TOPLEFT" then
rY = rel:GetTop()
rX = rel:GetLeft()
elseif relPoint == "TOP" then
rY = rel:GetTop()
rX = (rel:GetRight() + rel:GetLeft()) / 2
elseif relPoint == "BOTTOMRIGHT" then
rY = rel:GetBottom()
rX = rel:GetRight()
elseif relPoint == "BOTTOMLEFT" then
rY = rel:GetBottom()
rX = rel:GetLeft()
elseif relPoint == "BOTTOM" then
rY = rel:GetBottom()
rX = (rel:GetRight() + rel:GetLeft()) / 2
elseif relPoint == "CENTER" then
rY = (rel:GetTop() + rel:GetBottom()) / 2
rX = (rel:GetRight() + rel:GetLeft()) / 2
elseif relPoint == "LEFT" then
rY = (rel:GetTop() + rel:GetBottom()) / 2
rX = rel:GetLeft()
elseif relPoint == "RIGHT" then
rY = (rel:GetTop() + rel:GetBottom()) / 2
rX = rel:GetRight()
else
return
end
if rel.GetEffectiveScale then
rY = rY * rel:GetEffectiveScale()
rX = rX * rel:GetEffectiveScale()
else
rY = rY * UIParent:GetEffectiveScale()
rX = rX * UIParent:GetEffectiveScale()
end
end
if frame:GetLeft() then
if point == "TOPRIGHT" then
pY = frame:GetTop()
pX = frame:GetRight()
elseif point == "TOPLEFT" then
pY = frame:GetTop()
pX = frame:GetLeft()
elseif point == "TOP" then
pY = frame:GetTop()
pX = (frame:GetRight() + frame:GetLeft()) / 2
elseif point == "BOTTOMRIGHT" then
pY = frame:GetBottom()
pX = frame:GetRight()
elseif point == "BOTTOMLEFT" then
pY = frame:GetBottom()
pX = frame:GetLeft()
elseif point == "BOTTOM" then
pY = frame:GetBottom()
pX = (frame:GetRight() + frame:GetLeft()) / 2
elseif point == "CENTER" then
pY = (frame:GetTop() + frame:GetBottom()) / 2
pX = (frame:GetRight() + frame:GetLeft()) / 2
elseif point == "LEFT" then
pY = (frame:GetTop() + frame:GetBottom()) / 2
pX = frame:GetLeft()
elseif point == "RIGHT" then
pY = (frame:GetTop() + frame:GetBottom()) / 2
pX = frame:GetRight()
else
return
end
if frame.GetEffectiveScale then
pY = pY * frame:GetEffectiveScale()
pX = pX * frame:GetEffectiveScale()
else
pY = pY * UIParent:GetEffectiveScale()
pX = pX * UIParent:GetEffectiveScale()
end
end
if rY and rX and pY and pX then
rX = pX - rX
rY = pY - rY
if frame.GetEffectiveScale then
rY = rY / frame:GetEffectiveScale()
rX = rX / frame:GetEffectiveScale()
else
rY = rY / UIParent:GetEffectiveScale()
rX = rX / UIParent:GetEffectiveScale()
end
else
rX = 0
rY = 0
end
--print(point, rel:GetName(), relPoint, rX, rY)
return {point, rel:GetName(), relPoint, rX, rY}
end
local frame = CreateFrame("Frame", "TestFrame", UIParent)
frame:SetSize(400, 200)
frame:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", 0, -50)
frame:SetClampedToScreen(true)
frame.backdrop = {
bgFile = "Interface\\Buttons\\WHITE8X8",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true,
tileSize = 16,
edgeSize = 14,
insets = {left = 3, right = 3, top = 3, bottom = 3},
}
frame:SetBackdrop(frame.backdrop)
frame:SetBackdropColor(0.0, 0.0, 0.0, 0.5)
frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
-- Frame Hooks
hooksecurefunc(frame, "SetPoint", function(self)
if self.moving then
return
end
self.moving = true
self:SetMovable(true)
print("SetPoint")
local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
local x = math.round(pos[4])
local y = math.round(pos[5])
self:ClearAllPoints()
self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
self:SetMovable(false)
self.moving = nil
end)
hooksecurefunc(frame, "StopMovingOrSizing", function(self)
self:SetMovable(true)
print("StopMovingOrSizing")
local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
local x = math.round(pos[4])
local y = math.round(pos[5])
self:ClearAllPoints()
self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
self:SetMovable(false)
end)
frame:HookScript("OnSizeChanged", function(self)
self:SetSize(math.round(self:GetWidth()), math.round(self:GetHeight()))
end)
-- Parent Hooks
local point, relativeTo, relativePoint, xOffset, yOffset = frame:GetPoint(1)
hooksecurefunc(relativeTo, "SetPoint", function(self)
if self.moving then
return
end
self.moving = true
self:SetMovable(true)
print("Parent: SetPoint")
local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
local x = math.round(pos[4])
local y = math.round(pos[5])
self:ClearAllPoints()
self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
self:SetMovable(false)
self.moving = nil
end)
hooksecurefunc(relativeTo, "StopMovingOrSizing", function(self)
self:SetMovable(true)
print("Parent: StopMovingOrSizing")
local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
local x = math.round(pos[4])
local y = math.round(pos[5])
self:ClearAllPoints()
self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
self:SetMovable(false)
end)
relativeTo:HookScript("OnSizeChanged", function(self)
local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
local x = math.round(pos[4])
local y = math.round(pos[5])
self:ClearAllPoints()
self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
end)
-- Moving and Resizing functions
frame:EnableMouse(true)
--frame:SetMaxResize(800, 400)
frame:SetMinResize(40, 40)
frame:SetScript("OnMouseDown", function(self, button)
if button == "LeftButton" then
self:SetMovable(true)
self:StartMoving()
end
end)
frame:SetScript("OnMouseUp", function(self, button)
if button == "LeftButton" then
self:StopMovingOrSizing()
self:SetMovable(false)
local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
local x = math.round(pos[4])
local y = math.round(pos[5])
self:ClearAllPoints()
self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
end
end)
frame.br = CreateFrame("Frame", nil, frame)
frame.br:SetPoint("TOPLEFT", frame, "BOTTOMRIGHT", -15, 15)
frame.br:SetSize(12, 12)
frame.br:EnableMouse(true)
frame.br.texture = frame.br:CreateTexture(nil, "OVERLAY")
frame.br.texture:SetPoint("TOPLEFT", frame.br, "TOPLEFT", 0, 0)
frame.br.texture:SetSize(12, 12)
frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
frame.br:SetScript("OnEnter", function(self)
frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
end)
frame.br:SetScript("OnLeave", function(self)
frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
end)
frame.br:SetScript("OnMouseDown", function(self, button)
if button == "LeftButton" then
frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
frame:SetResizable(true)
frame:StartSizing("BottomRight")
end
end)
frame.br:SetScript("OnMouseUp", function(self, button)
frame:StopMovingOrSizing()
frame:SetResizable(false)
frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
end)