local Y=require((game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):WaitForChild("\078\101\118\101\114\109\111\114\101"))local w=Y("\083\112\114\105\110\103")local T={}T.ClassName="\083\099\114\111\108\108\077\111\100\101\108"T.__index=T T._min=0 T._max=100 T._viewSize=50 function T.new()local Y=setmetatable({},T)Y._spring=w.new(0)Y._spring.Speed=20 return Y end function T._getTimesOverBounds(w,Y)return w:GetDisplacementPastBounds(Y)/w.BackBounceInputRange end function T.GetDisplacementPastBounds(w,Y)if Y>w.ContentMax then return Y-w.ContentMax elseif Y<w.ContentMin then return Y else return 0 end end function T.GetScale(w,Y)return 1-.5^math.abs(Y)end function T.__index(w,Y)if Y=="\084\111\116\097\108\067\111\110\116\101\110\116\076\101\110\103\116\104"then return w._max-w._min elseif Y=="\086\105\101\119\083\105\122\101"then return w._viewSize elseif Y=="\077\097\120"then return w._max elseif Y=="\067\111\110\116\101\110\116\077\097\120"then if w._max<=w.ContentMin+w._viewSize then return w.ContentMin else return w._max-w._viewSize end elseif Y=="\077\105\110"or Y=="\067\111\110\116\101\110\116\077\105\110"then return w._min elseif Y=="\080\111\115\105\116\105\111\110"then return w._spring.Position elseif Y=="\066\097\099\107\066\111\117\110\099\101\073\110\112\117\116\082\097\110\103\101"then return w._viewSize elseif Y=="\066\097\099\107\066\111\117\110\099\101\082\101\110\100\101\114\082\097\110\103\101"then return w._viewSize elseif Y=="\067\111\110\116\101\110\116\083\099\114\111\108\108\080\101\114\099\101\110\116\083\105\122\101"then if w.TotalContentLength==0 then return 0 end return w._viewSize/w.TotalContentLength elseif Y=="\082\101\110\100\101\114\101\100\067\111\110\116\101\110\116\083\099\114\111\108\108\080\101\114\099\101\110\116\083\105\122\101"then local Y=w.Position return w.ContentScrollPercentSize*(1-w:GetScale(w:_getTimesOverBounds(Y)))elseif Y=="\067\111\110\116\101\110\116\083\099\114\111\108\108\080\101\114\099\101\110\116"then return(w.Position-w._min)/(w.TotalContentLength-w._viewSize)elseif Y=="\082\101\110\100\101\114\101\100\067\111\110\116\101\110\116\083\099\114\111\108\108\080\101\114\099\101\110\116"then local Y=w.ContentScrollPercent if Y<0 then return 0 elseif Y>1 then return 1 else return Y end elseif Y=="\066\111\117\110\100\101\100\082\101\110\100\101\114\080\111\115\105\116\105\111\110"then local Y=w.Position local T=w:_getTimesOverBounds(Y)local t=w:GetScale(T)if T>0 then return-w.ContentMax-t*w.BackBounceRenderRange elseif T<0 then return w.ContentMin+t*w.BackBounceRenderRange else return-Y end elseif Y=="\086\101\108\111\099\105\116\121"then return w._spring.Velocity elseif Y=="\084\097\114\103\101\116"then return w._spring.Target elseif Y=="\065\116\082\101\115\116"then return math.abs(w._spring.Target-w._spring.Position)<1e-05 and math.abs(w._spring.Velocity)<1e-05 elseif T[Y]then return T[Y]else error(("\091\083\099\114\111\108\108\077\111\100\101\108\093 - \'\037\115\' \105\115 \110\111\116 \097 \118\097\108\105\100 \109\101\109\098\101\114"):format(tostring(Y)))end end function T.__newindex(t,Y,w)if T[Y]or Y=="\095\115\112\114\105\110\103"then rawset(t,Y,w)elseif Y=="\077\105\110"or Y=="\067\111\110\116\101\110\116\077\105\110"then t._min=w elseif Y=="\077\097\120"then t._max=w t.Target=t.Target elseif Y=="\084\111\116\097\108\067\111\110\116\101\110\116\076\101\110\103\116\104"then t.Max=t._min+w elseif Y=="\086\105\101\119\083\105\122\101"then t._viewSize=w elseif Y=="\080\111\115\105\116\105\111\110"then t._spring.Position=w elseif Y=="\084\097\114\103\101\116\067\111\110\116\101\110\116\083\099\114\111\108\108\080\101\114\099\101\110\116"then t.Target=t._min+w*(t.TotalContentLength-t._viewSize)elseif Y=="\067\111\110\116\101\110\116\083\099\114\111\108\108\080\101\114\099\101\110\116"then t.Position=t._min+w*(t.TotalContentLength-t._viewSize)elseif Y=="\084\097\114\103\101\116"then if w>t.ContentMax then w=t.ContentMax elseif w<t.ContentMin then w=t.ContentMin end t._spring.Target=w elseif Y=="\086\101\108\111\099\105\116\121"then t._spring.Velocity=w else error(("\091\083\099\114\111\108\108\077\111\100\101\108\093 - \'\037\115\' \105\115 \110\111\116 \097 \118\097\108\105\100 \109\101\109\098\101\114"):format(tostring(Y)))end end return T
--- Scrolling model for scrolling frame
-- @module ScrollModel

local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

local Spring = require("Spring")

local ScrollModel = {}
ScrollModel.ClassName = "ScrollModel"
ScrollModel.__index = ScrollModel
ScrollModel._min = 0
ScrollModel._max = 100
ScrollModel._viewSize = 50

function ScrollModel.new()
	local self = setmetatable({}, ScrollModel)

	self._spring = Spring.new(0)
	self._spring.Speed = 20

	return self
end

function ScrollModel:_getTimesOverBounds(position)
	return self:GetDisplacementPastBounds(position) / self.BackBounceInputRange
end

function ScrollModel:GetDisplacementPastBounds(position)
	if position > self.ContentMax then
		return position - self.ContentMax
	elseif position < self.ContentMin then
		return position
	else
		return 0
	end
end

function ScrollModel:GetScale(timesOverBounds)
	return 1 - 0.5 ^ math.abs(timesOverBounds)
end

function ScrollModel:__index(index)
	if index == "TotalContentLength" then
		return self._max - self._min
	elseif index == "ViewSize" then
		return self._viewSize
	elseif index == "Max" then
		return self._max
	elseif index == "ContentMax" then
		if self._max <= self.ContentMin + self._viewSize then
			return self.ContentMin
		else
			return self._max - self._viewSize -- Compensate for AnchorPoint = 0
		end
	elseif index == "Min" or index == "ContentMin" then
		return self._min
	elseif index == "Position" then
		return self._spring.Position
	elseif index == "BackBounceInputRange" then
		return self._viewSize -- Maximum distance we can drag past the end
	elseif index == "BackBounceRenderRange" then
		return self._viewSize
	elseif index == "ContentScrollPercentSize" then
		if self.TotalContentLength == 0 then
			return 0
		end

		return (self._viewSize / self.TotalContentLength)
	elseif index == "RenderedContentScrollPercentSize" then
		local Position = self.Position
		return self.ContentScrollPercentSize * (1-self:GetScale(self:_getTimesOverBounds(Position)))
	elseif index == "ContentScrollPercent" then
		return (self.Position - self._min) / (self.TotalContentLength - self._viewSize)
	elseif index == "RenderedContentScrollPercent" then
		local Percent = self.ContentScrollPercent
		if Percent < 0 then
			return 0
		elseif Percent > 1 then
			return 1
		else
			return Percent
		end
	elseif index == "BoundedRenderPosition" then
		local position = self.Position
		local timesOverBounds = self:_getTimesOverBounds(position)
		local scale = self:GetScale(timesOverBounds)
		if timesOverBounds > 0 then
			return -self.ContentMax - scale*self.BackBounceRenderRange
		elseif timesOverBounds < 0 then
			return self.ContentMin + scale*self.BackBounceRenderRange
		else
			return -position
		end
	elseif index == "Velocity" then
		return self._spring.Velocity
	elseif index == "Target" then
		return self._spring.Target
	elseif index == "AtRest" then
		return math.abs(self._spring.Target - self._spring.Position) < 1e-5 and math.abs(self._spring.Velocity) < 1e-5
	elseif ScrollModel[index] then
		return ScrollModel[index]
	else
		error(("[ScrollModel] - '%s' is not a valid member"):format(tostring(index)))
	end
end

function ScrollModel:__newindex(index, value)
	if ScrollModel[index] or index == "_spring" then
		rawset(self, index, value)
	elseif index == "Min" or index == "ContentMin" then
		self._min = value
	elseif index == "Max" then
		self._max = value
		self.Target = self.Target -- Force update!
	elseif index == "TotalContentLength" then
		self.Max = self._min + value
	elseif index == "ViewSize" then
		self._viewSize = value
	elseif index == "Position" then
		self._spring.Position = value
	elseif index == "TargetContentScrollPercent" then
		self.Target = self._min + value * (self.TotalContentLength - self._viewSize)
	elseif index == "ContentScrollPercent" then
		self.Position = self._min + value * (self.TotalContentLength - self._viewSize)
	elseif index == "Target" then
		if value > self.ContentMax then
			value = self.ContentMax
		elseif value < self.ContentMin then
			value = self.ContentMin
		end
		self._spring.Target = value
	elseif index == "Velocity" then
		self._spring.Velocity = value
	else
		error(("[ScrollModel] - '%s' is not a valid member"):format(tostring(index)))
	end
end

return ScrollModel