local g="\078\101\120\117\115\066\111\117\110\100\105\110\103\083\105\122\101\067\111\110\115\116\114\097\105\110\116"local A=(require(script.Parent.Parent.Parent:WaitForChild("\078\101\120\117\115\080\108\117\103\105\110\070\114\097\109\101\119\111\114\107\080\114\111\106\101\099\116"))):GetContext(script)local I=A:GetResource("\066\097\115\101\046\078\101\120\117\115\067\111\110\116\097\105\110\101\114")local O=I:Extend()O:SetClassName(g)A:SetContextResource(O)function O.__new(O,A)O:InitializeSuper()O.Name=g local Y={}O.FrameConnections=Y local z,q local a,i local W,j local C,S=0,0 local J,c=0,0 if A:IsA(I.ClassName)then A=A:GetWrappedInstance()end local function M(g)local A,I=g.AbsoluteSize,g.AbsolutePosition local O,Y=A.X,A.Y local z,q=I.X,I.Y if O>0 then z=z+O end if Y>0 then q=q+Y end return z,q end local function r(g,A)local I={}if A~=true and not g.Visible then return{}end table.insert(I,g)for g,A in pairs(g:GetChildren())do if A:IsA("\070\114\097\109\101")and A.Visible then for g,A in pairs(r(A))do table.insert(I,A)end end end return I end local function u()if z and q then return end local g,I=A.AbsolutePosition.X,A.AbsolutePosition.Y local O,Y=g,I local u,d=g,I local L,o for g,I in pairs(r(A,true))do if I.Visible and I~=A then local g,A=M(I)if not z then if g>O then if O>u then u=O W=a end O=g a=I elseif g>u then u=g end end if not q then if A>Y then if Y>d then d=Y j=i end Y=A elseif A>d then d=A i=I end end end end J,c=u-g,d-I C,S=O-g,Y-I end local function d()A.Size=UDim2.new(z or UDim.new(0,C),q or UDim.new(0,S))end local function L(g)local A=Y[g]if A then for g,A in pairs(A)do A:Disconnect()end Y[g]=nil end u()d()end local function o(g)if g:IsA("\070\114\097\109\101")and not Y[g]then local I,O local r,o local function K()local Y,L=g.Size,g.Position local K,R=Y.X,Y.Y local b,e=L.X,L.Y if z and q or K==I and(b==r and q)or R==O and(e==o and z)then return end I=K O=R r=b o=e local t,k=M(g)local w,v=t-A.AbsolutePosition.X,k-A.AbsolutePosition.Y local y,Q=false,false if g==a then if w>J then C=w else y=true end elseif g==W then if w>C then J=C C=w elseif w<J then y=true end elseif w>C then y=true end if g==i then if v>c then S=v else Q=true end elseif g==j then if v>S then c=S S=v elseif v<c then Q=true end elseif v>S then Q=true end if y or Q then u()end u()d()end local function R()u()d()end local b={}local e=false table.insert(b,(g:GetPropertyChangedSignal("\086\105\115\105\098\108\101")):Connect(R))table.insert(b,(g:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\082\111\116\097\116\105\111\110")):Connect(K))table.insert(b,(g:GetPropertyChangedSignal("\065\110\099\104\111\114\080\111\105\110\116")):Connect(K))table.insert(b,(g:GetPropertyChangedSignal("\080\111\115\105\116\105\111\110")):Connect(K))table.insert(b,(g:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\083\105\122\101")):Connect(function()if not e then K()else e=true end end))table.insert(b,(g:GetPropertyChangedSignal("\083\105\122\101")):Connect(function()e=true K()end))table.insert(b,(g:GetPropertyChangedSignal("\080\097\114\101\110\116")):Connect(function()if not g:IsDescendantOf(A)then L(g)else R()end end))Y[g]=b end end O.DescendantAddedConnection=A.DescendantAdded:Connect(function(g)o(g)u()d()end)O.SizeXOverrideConnection=(O:GetPropertyChangedSignal("\083\105\122\101\088\079\118\101\114\114\105\100\101")):Connect(function()z=O.SizeXOverride u()d()end)O.SizeYOverrideConnection=(O:GetPropertyChangedSignal("\083\105\122\101\089\079\118\101\114\114\105\100\101")):Connect(function()q=O.SizeYOverride u()d()end)for g,A in pairs(A:GetDescendants())do o(A)end u()d()end function O.Destroy(g)g.DescendantAddedConnection:Disconnect()g.SizeXOverrideConnection:Disconnect()g.SizeYOverrideConnection:Disconnect()local A={}for g,I in pairs(g.FrameConnections)do table.insert(A,g)for g,A in pairs(I)do A:Disconnect()end end for A,I in pairs(A)do g.FrameConnections[I]=nil end end return O
--[[
TheNexusAvenger

Constraint that is applied to a frame to set the
size as a bounding size.
--]]

local CLASS_NAME = "NexusBoundingSizeConstraint"



local NexusPluginFramework = require(script.Parent.Parent.Parent:WaitForChild("NexusPluginFrameworkProject")):GetContext(script)
local NexusContainer = NexusPluginFramework:GetResource("Base.NexusContainer")

local NexusBoundingSizeConstraint = NexusContainer:Extend()
NexusBoundingSizeConstraint:SetClassName(CLASS_NAME)
NexusPluginFramework:SetContextResource(NexusBoundingSizeConstraint)



--[[
Creates a Nexus Bounding Size Constraint object.
--]]
function NexusBoundingSizeConstraint:__new(Frame)
	self:InitializeSuper()
	self.Name = CLASS_NAME
	
	local FrameConnections = {}
	self.FrameConnections = FrameConnections
	local SizeXOverride,SizeYOverride
	local BoundingFrameX,BoundingFrameY
	local SecondaryBoundingFrameX,SecondaryBoundingFrameY
	local BoundingSizeX,BoundingSizeY = 0,0
	local SecondBoundingSizeX,SecondBoundingSizeY = 0,0
	
	--Unwrap the frame.
	if Frame:IsA(NexusContainer.ClassName) then
		Frame = Frame:GetWrappedInstance()
	end
	
	--[[
	Returns the corner position of the frame.
	--]]
	local function GetCornerPosition(Frame)
		local AbsoluteSize,AbsolutePosition = Frame.AbsoluteSize,Frame.AbsolutePosition
		local SizeX,SizeY = AbsoluteSize.X,AbsoluteSize.Y
		local PosX,PosY = AbsolutePosition.X,AbsolutePosition.Y
		
		--Add to the PosX and PosY.
		if SizeX > 0 then
			PosX = PosX + SizeX
		end
		if SizeY > 0 then
			PosY = PosY + SizeY
		end
		
		--Return the corner.
		return PosX,PosY
	end
	
	--[[
	Returns the visible frames.
	--]]
	local function GetVisibleFrames(ReferenceFrame,IgnoreFirstCheck)
		local Frames = {}
		
		--Return if the frame is invisible.
		if IgnoreFirstCheck ~= true and not ReferenceFrame.Visible then
			return {}
		end
		
		--Get the frames.
		table.insert(Frames,ReferenceFrame)
		for _,SubFrame in pairs(ReferenceFrame:GetChildren()) do
			if SubFrame:IsA("Frame") and SubFrame.Visible then
				for _,ChildFrame in pairs(GetVisibleFrames(SubFrame)) do
					table.insert(Frames,ChildFrame)
				end
			end
		end
		
		--Return the frames.
		return Frames
	end
	
	--[[
	Recalculates the bounding size of the frame.
	--]]
	local function RecalculateBoundingSize()
		--Return the size if both overrides are set.
		if SizeXOverride and SizeYOverride then
			return
		end
		
		--Get the starting position.
		local StartingPosX,StartingPosY = Frame.AbsolutePosition.X,Frame.AbsolutePosition.Y
		local MaxPosX,MaxPosY = StartingPosX,StartingPosY
		local SecondMaxPosX,SecondMaxPosY = StartingPosX,StartingPosY
		local NewBoundingFrameX,NewBoundingFrameY
		
		--Set the max position.
		for _,SubFrame in pairs(GetVisibleFrames(Frame,true)) do
			if SubFrame.Visible and SubFrame ~= Frame then
				local CornerPosX,CornerPosY = GetCornerPosition(SubFrame)
				
				--Update the max size X.
				if not SizeXOverride then
					if CornerPosX > MaxPosX then
						if MaxPosX > SecondMaxPosX then
							SecondMaxPosX = MaxPosX
							SecondaryBoundingFrameX = BoundingFrameX
						end
						MaxPosX = CornerPosX
						BoundingFrameX = SubFrame
					elseif CornerPosX > SecondMaxPosX then
						SecondMaxPosX = CornerPosX
					end
				end
				
				--Update the max size Y.
				if not SizeYOverride then
					if CornerPosY > MaxPosY then
						if MaxPosY > SecondMaxPosY then
							SecondMaxPosY = MaxPosY
							SecondaryBoundingFrameY = BoundingFrameY
						end
						MaxPosY = CornerPosY
					elseif CornerPosY > SecondMaxPosY then
						SecondMaxPosY = CornerPosY
						BoundingFrameY = SubFrame
					end
				end
			end
		end
		
		--Set the bounding size.
		SecondBoundingSizeX,SecondBoundingSizeY = SecondMaxPosX - StartingPosX,SecondMaxPosY - StartingPosY
		BoundingSizeX,BoundingSizeY = MaxPosX - StartingPosX,MaxPosY - StartingPosY
	end
	
	--[[
	Updates the bounding size.
	--]]
	local function UpdateBoundingSize()
		Frame.Size = UDim2.new(SizeXOverride or UDim.new(0,BoundingSizeX),SizeYOverride or UDim.new(0,BoundingSizeY))
	end
	
	--[[
	Disconnects the events when a frame is removed.
	--]]
	local function FrameRemoved(SubFrame)
		--Disconnect the connections.
		local Connections = FrameConnections[SubFrame]
		if Connections then
			for _,Connection in pairs(Connections) do
				Connection:Disconnect()
			end
			FrameConnections[SubFrame] = nil
		end
		
		--Update the bounding size.
		RecalculateBoundingSize()
		UpdateBoundingSize()
	end
	
	--[[
	Adds a new frame to track.
	--]]
	local function FrameAdded(SubFrame)
		if SubFrame:IsA("Frame") and not FrameConnections[SubFrame] then
			local LastSizeX,LastSizeY
			local LastPosX,LastPosY
			
			--[[
			Updates the size if it changes.
			--]]
			local function UpdateSize()
				--Get the current size.
				local Size,Position = SubFrame.Size,SubFrame.Position
				local SizeX,SizeY = Size.X,Size.Y
				local PosX,PosY = Position.X,Position.Y
				
				--Return if the non-overriden size hasn't changed.
				if (SizeXOverride and SizeYOverride) or (SizeX == LastSizeX and PosX == LastPosX and SizeYOverride) or (SizeY == LastSizeY and PosY == LastPosY and SizeXOverride) then
					return
				end
				
				--Update the last size.
				LastSizeX = SizeX
				LastSizeY = SizeY
				LastPosX = PosX
				LastPosY = PosY
				
				--Change the bounding size.
				local CornerPosX,CornerPosY = GetCornerPosition(SubFrame)
				local AbsoluteSizeX,AbsoluteSizeY = CornerPosX - Frame.AbsolutePosition.X,CornerPosY - Frame.AbsolutePosition.Y
				local RecalculateX,RecalculateY = false,false
				if SubFrame == BoundingFrameX then
					if AbsoluteSizeX > SecondBoundingSizeX then
						BoundingSizeX = AbsoluteSizeX
					else
						RecalculateX = true
					end
				elseif SubFrame == SecondaryBoundingFrameX then
					if AbsoluteSizeX > BoundingSizeX then
						SecondBoundingSizeX = BoundingSizeX
						BoundingSizeX = AbsoluteSizeX
					elseif AbsoluteSizeX < SecondBoundingSizeX then
						RecalculateX = true
					end
				elseif AbsoluteSizeX > BoundingSizeX then
					RecalculateX = true
				end
				
				if SubFrame == BoundingFrameY then
					if AbsoluteSizeY > SecondBoundingSizeY then
						BoundingSizeY = AbsoluteSizeY
					else
						RecalculateY = true
					end
				elseif SubFrame == SecondaryBoundingFrameY then
					if AbsoluteSizeY > BoundingSizeY then
						SecondBoundingSizeY = BoundingSizeY
						BoundingSizeY = AbsoluteSizeY
					elseif AbsoluteSizeY < SecondBoundingSizeY then
						RecalculateY = true
					end
				elseif AbsoluteSizeY > BoundingSizeY then
					RecalculateY = true
				end
				
				--Recalculate the bounding size if needed.
				if RecalculateX or RecalculateY then
					RecalculateBoundingSize()
				end
				
				--Update the bouding size.
				RecalculateBoundingSize()
				UpdateBoundingSize()
			end
			
			--[[
			Force-recalculates the size.
			--]]
			local function ForceRecalculateSize()
				RecalculateBoundingSize()
				UpdateBoundingSize()
			end
			
			--Add the connections.
			local Connections = {}
			local SizeManuallyChanged = false
			table.insert(Connections,SubFrame:GetPropertyChangedSignal("Visible"):Connect(ForceRecalculateSize))
			table.insert(Connections,SubFrame:GetPropertyChangedSignal("AbsoluteRotation"):Connect(UpdateSize)) --Hack that allows for updates with List Constraints
			table.insert(Connections,SubFrame:GetPropertyChangedSignal("AnchorPoint"):Connect(UpdateSize))
			table.insert(Connections,SubFrame:GetPropertyChangedSignal("Position"):Connect(UpdateSize))
			table.insert(Connections,SubFrame:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
				if not SizeManuallyChanged then
					UpdateSize()
				else
					SizeManuallyChanged = true
				end
			end))
			table.insert(Connections,SubFrame:GetPropertyChangedSignal("Size"):Connect(function()
				SizeManuallyChanged = true
				UpdateSize()
			end))
			table.insert(Connections,SubFrame:GetPropertyChangedSignal("Parent"):Connect(function()
				if not SubFrame:IsDescendantOf(Frame) then
					FrameRemoved(SubFrame)
				else
					ForceRecalculateSize()
				end
			end))
			
			--Store the connections.
			FrameConnections[SubFrame] = Connections
		end
	end
	
	--Set up the connections for adding/removing frames.
	self.DescendantAddedConnection = Frame.DescendantAdded:Connect(function(Frame)
		FrameAdded(Frame)
		RecalculateBoundingSize()
		UpdateBoundingSize()
	end)
	
	--Set up the connections for overrides.
	self.SizeXOverrideConnection = self:GetPropertyChangedSignal("SizeXOverride"):Connect(function()
		SizeXOverride = self.SizeXOverride
		RecalculateBoundingSize()
		UpdateBoundingSize()
	end)
	self.SizeYOverrideConnection = self:GetPropertyChangedSignal("SizeYOverride"):Connect(function()
		SizeYOverride = self.SizeYOverride
		RecalculateBoundingSize()
		UpdateBoundingSize()
	end)
	
	--Add the frames.
	for _,Frame in pairs(Frame:GetDescendants()) do
		FrameAdded(Frame)
	end
	
	--Resize the frame.
	RecalculateBoundingSize()
	UpdateBoundingSize()
end

--[[
Destroys the constraint.
--]]
function NexusBoundingSizeConstraint:Destroy()
	--Disconnect the connections.
	self.DescendantAddedConnection:Disconnect()
	self.SizeXOverrideConnection:Disconnect()
	self.SizeYOverrideConnection:Disconnect()
	local Frames = {}
	for Frame,FrameConnections in pairs(self.FrameConnections) do
		table.insert(Frames,Frame)
		for _,Connection in pairs(FrameConnections) do
			Connection:Disconnect()
		end
	end
	
	--Clear the connections.
	for _,Frame in pairs(Frames) do
		self.FrameConnections[Frame] = nil
	end
end



return NexusBoundingSizeConstraint