local addonName, Butterfly = ...; --[[============ Since the SocialPostFrame is forbidden, we need OnUpdate shenanigans to "SetPoint" to it. The FauxFrame is a strata-, size-, position-, and anchor-matched overlay, to which anything else should SetPoint. EVERY movement must be exact. Any desynchronization is *unrecoverable*. StartMoving captures init position, and StopMoving calls an extra UpdatePosition, to ensure we don't lose a single frame of movement. The hairiest bit is that the SocialPostFrame is movable, which means that its :StopMoving may change the attachment point, from CENTER to the nearest edge or corner. That WOULD be perfectly ignorable, except that when it calls :SetSize, it uses THAT point as the fixed anchor. So, the FauxFrame has to explicitly reattach itself appropriately (since it isn't itself being dragged). Not all of the related code is as clean as I'd like, but it works, and hopefully this never needs to change. TODO: - Clean up the UIScale stuff? - Fix the hacky detach/reattach --============]] local function GetScaledCursorPosition() local x, y = GetCursorPosition() local scale = UIParent:GetScale() return x/scale, y/scale end local FauxFrame = CreateFrame("Frame", "ButterflyFauxFrame", UIParent) FauxFrame:SetFrameStrata("HIGH") FauxFrame.MessageFrame = CreateFrame("Frame", "ButterflyFauxFrameMessageFrame", FauxFrame) FauxFrame:Hide() -- so that the Gallery's OnShow script can run initially FauxFrame.sumCursorMovementX = 0 FauxFrame.sumCursorMovementY = 0 function FauxFrame:UpdateSocialPostFrameOffset() local newCursorX, newCursorY = GetScaledCursorPosition() local deltaX = newCursorX - self.oldCursorX local deltaY = newCursorY - self.oldCursorY self.oldCursorX = newCursorX self.oldCursorY = newCursorY self.sumCursorMovementX = self.sumCursorMovementX + deltaX self.sumCursorMovementY = self.sumCursorMovementY + deltaY end function FauxFrame:StartMoving() self.isMoving = true self:Detach() end function FauxFrame:StopMoving() self.isMoving = false self:Reattach() end function FauxFrame:UpdatePosition() self:ClearAllPoints() self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", self.UIParentWidth/2 + self.sumCursorMovementX - self:GetWidth()/2, -self.UIParentHeight/2 + self.sumCursorMovementY + self:GetHeight()/2) end function FauxFrame:Detach() local distanceFromLeft = self:GetLeft() local distanceFromTop = self.UIParentHeight - self:GetTop() -- This is a hack and a half, but it works (it's because we fuck with attachment in the first place so resizes work properly) self.sumCursorMovementX = self:GetLeft() + self:GetWidth()/2 - self.UIParentWidth/2 self.sumCursorMovementY = self:GetTop() - self:GetHeight()/2 - self.UIParentHeight/2 end function FauxFrame:Reattach() local distances = {} distances["LEFT"] = self:GetLeft() distances["RIGHT"] = self.UIParentWidth - self:GetRight() distances["BOTTOM"] = self:GetBottom() distances["TOP"] = self.UIParentHeight - self:GetTop() local nearToLeft = distances["LEFT"] < math.abs(self.sumCursorMovementX) local nearToRight = distances["RIGHT"] < math.abs(self.sumCursorMovementX) local nearToTop = distances["TOP"] < math.abs(self.sumCursorMovementY) local nearToBottom = distances["BOTTOM"] < math.abs(self.sumCursorMovementY) self:ClearAllPoints() if nearToLeft then if nearToTop then self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", distances["LEFT"], -distances["TOP"]) elseif nearToBottom then self:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", distances["LEFT"], distances["BOTTOM"]) else self:SetPoint("LEFT", UIParent, "LEFT", distances["LEFT"], self.sumCursorMovementY) end elseif nearToRight then if nearToTop then self:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", -distances["RIGHT"], -distances["TOP"]) elseif nearToBottom then self:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -distances["RIGHT"], distances["BOTTOM"]) else self:SetPoint("RIGHT", UIParent, "RIGHT", -distances["RIGHT"], self.sumCursorMovementY) end else if nearToTop then self:SetPoint("TOP", UIParent, "TOP", self.sumCursorMovementX, -distances["TOP"]) elseif nearToBottom then self:SetPoint("BOTTOM", UIParent, "BOTTOM", self.sumCursorMovementX, distances["BOTTOM"]) else self:SetPoint("CENTER", UIParent, "CENTER", self.sumCursorMovementX, self.sumCursorMovementY) end end end function FauxFrame:OnUpdate(elapsed) if self.isMoving then self:UpdateSocialPostFrameOffset() self:UpdatePosition() end end function FauxFrame:Resize(width, height) self:SetSize(width, height) end Butterfly.FauxFrame = FauxFrame function Butterfly:InitializeFauxFrame() hooksecurefunc(SocialPostFrame, "StartMoving", function() self.FauxFrame.oldCursorX, self.FauxFrame.oldCursorY = GetScaledCursorPosition() self.FauxFrame:StartMoving() end) hooksecurefunc(SocialPostFrame, "StopMovingOrSizing", function() self.FauxFrame:UpdateSocialPostFrameOffset() self.FauxFrame:UpdatePosition() self.FauxFrame:StopMoving() end) self.FauxFrame:SetSize(SOCIAL_DEFAULT_FRAME_WIDTH, SOCIAL_DEFAULT_FRAME_HEIGHT) self.FauxFrame:SetPoint("CENTER") FauxFrame.MessageFrame:SetSize(348, 92) FauxFrame.MessageFrame:SetPoint("BOTTOM", 0, 62) -- Can't use HookScript("OnShow") because SocialPostFrame is forbidden -- Can't hook SocialPostFrame_OnShow because it's referenced inline in the XML and the new hook won't be called hooksecurefunc(SocialPostFrame, "Show", function() self.FauxFrame:Show() end) hooksecurefunc(SocialPostFrame, "Hide", function() self.FauxFrame:Hide() end) hooksecurefunc(SocialPostFrame, "SetSize", function(SPF, width, height) self.FauxFrame:Resize(width, height) end) self.FauxFrame:SetScript("OnUpdate", function(self, elapsed) self:OnUpdate(elapsed) end) self.FauxFrame.UIScale = UIParent:GetScale() self.FauxFrame.UIParentWidth = UIParent:GetWidth() self.FauxFrame.UIParentHeight = UIParent:GetHeight() FauxFrame:RegisterEvent("UI_SCALE_CHANGED") FauxFrame:SetScript("OnEvent", function(self, event) if event == "UI_SCALE_CHANGED" then local newScale = UIParent:GetScale() self.sumCursorMovementX = self.sumCursorMovementX*newScale/self.UIScale self.sumCursorMovementY = self.sumCursorMovementY*newScale/self.UIScale self.UIScale = newScale self.UIParentWidth = UIParent:GetWidth() self.UIParentHeight = UIParent:GetHeight() end end) end