local A=script.Parent.Parent local m=require(A:WaitForChild("\076\097\122\121\076\111\097\100\101\114"))local Y=A:WaitForChild("\068\101\102\097\117\108\116\115")local x=game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")local a=game:GetService("\082\117\110\083\101\114\118\105\099\101")local s=Y:WaitForChild("\083\108\105\100\101\114\070\114\097\109\101\088")local t=Y:WaitForChild("\083\108\105\100\101\114\070\114\097\109\101\089")local I=.01 local Q=.1 local Z=.35 local W=Enum.KeyCode.Thumbstick2 local D={}D.__index=D D.__type="\083\108\105\100\101\114"function D.__tostring(A)return D.__type end function D.new(A,Y)local x=setmetatable({},D)x._Maid=m.Utilities.Maid.new()x._Spring=m.Utilities.Spring.new(1,.1,1,0)x._Axis=Y or"\120"x._ChangedBind=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")x._ClickedBind=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")x.Interval=0 x.IsActive=true x.TweenClick=true x.Inverted=false x.Frame=A x.Changed=x._ChangedBind.Event x.Clicked=x._ClickedBind.Event x.DragStart=nil x.DragStop=nil init(x)x:Set(.5)return x end function D.Create(A)local m=nil if not A or A=="\120"then m=D.new(s:Clone(),A)else m=D.new(t:Clone(),A)m.Inverted=true end return m end function init(A)local Y=A.Frame local s=Y.Dragger local t=Y.Background local D=A._Axis local o=A._Maid local P=A._Spring local q=m.Classes.Dragger.new(s)A.DragStart=q.DragStart A.DragStop=q.DragStop o:Mark(Y)o:Mark(A._ChangedBind)o:Mark(A._ClickedBind)o:Mark(function()q:Destroy()end)local function i(A,m)if D=="\121"then A,m=m,A end return UDim2.new(A,0,m,0)end local c=-1 local j,r local B=false local function b()j,r=getBounds(A)t.Size=i(r/Y.AbsoluteSize[D],1)c=-1 end o:Mark((Y:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\083\105\122\101")):Connect(b))o:Mark((Y:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\080\111\115\105\116\105\111\110")):Connect(b))o:Mark((Y:GetPropertyChangedSignal("\080\097\114\101\110\116")):Connect(b))local p=0 local M=0 local v=false o:Mark(s.SelectionGained:Connect(function()v=true end))o:Mark(s.SelectionLost:Connect(function()v=false end))o:Mark(x.InputChanged:Connect(function(A,m)if m and A.KeyCode==W then local m=A.Position p=math.abs(m[D])>Z and math.sign(m[D])or 0 end end))o:Mark(q.DragChanged:Connect(function(m,Y,x)if A.IsActive then A:Set((Y.Position[D]-j)/r,false)end end))o:Mark(Y.InputBegan:Connect(function(m)if m.UserInputType==Enum.UserInputType.MouseButton1 or m.UserInputType==Enum.UserInputType.Touch then local Y=(m.Position[D]-j)/r A._ClickedBind:Fire(math.clamp(Y,0,1))if A.IsActive then A:Set(Y,A.TweenClick)end end end))o:Mark(a.RenderStepped:Connect(function(m)if not B then b()B=true end if v then local Y=tick()if A.Interval<=0 then A:Set(A:Get()+((p*I)*m)*60)elseif Y-M>Q then M=Y A:Set(A:Get()+A.Interval*p)end end P:Update(m)local x=P.x if x~=c then local m=Y.AbsolutePosition[D]local a=Y.AbsoluteSize[D]local t=((j+x*r)-m)/a s.Position=i(t,.5)A._ChangedBind:Fire(A:Get())c=x end end))end function getBounds(A)local m=A.Frame local Y=m.Dragger local x=A._Axis local a=m.AbsolutePosition[x]+Y.AbsoluteSize[x]/2 local s=m.AbsoluteSize[x]-Y.AbsoluteSize[x]return a,s end function D.Get(A)local m=A._Spring.x if A.Inverted then m=1-m end return m end function D.Set(Y,A,m)local x=Y._Spring local a=math.clamp(A,0,1)if Y.Interval>0 then a=math.floor(a/Y.Interval+.5)*Y.Interval end x.t=a x.instant=not m end function D.Destroy(A)A._Maid:Sweep()A.Frame:Destroy()A.Changed=nil A.Clicked=nil A.StartDrag=nil A.StopDrag=nil A.Frame=nil end return D
--[[
Classes.Slider

This class creates a slider object which can be dragged for different values.

Constructors:
	new(frame [instance], axis [string])
		> Slider frames must have the following format:
			>> SliderFrame
				>>> Dragger
				>>> Background
		> axis defines if the slider is horizontal "x" or vertical "y"
	Create(axis [string])
		> Creates a slider frame from the default, simply define whether it's horizontal "x" or vertical "y".

Properties:
	Frame [instance]
		> The container frame for the slider. Can be used for positioning and resizing.
	Interval [number] [0, 1]
		> Set this to force an interval step on the slider. For example if you only wanted steps of 1/10th then you'd write
		> Slider.Interval = 0.1
	IsActive [boolean]
		> When true the slider can be interacted with by the user, when false its values can only be set by the developer.
	TweenClick [boolean]
		> If true then when the user clicks on the slider the dragger will tween to that target. If not it will be instant.
	Inverted [boolean]
		> If true then the value of the slider will be inverted (e.g. when horizontal the right-most position will be zero and left-most 1)
		> This is useful for when you have a vertical slider as typically users envision the down-most position to be zero.

Methods:
	:Get() [number]
		> Returns the slider position from 0 to 1
	:Set(value [number], doTween [boolean]) [void]
		> Sets the slider to a specific position or closest possible if interval > 0. If doTween is true then the slider will tween to that position.
	:Destroy() [void]
		> Destroys the slider frame and all the events, etc that were running it

Events:
	.Changed:Connect(function(value [number])
		> When the slider's position changes this fires the slider's current position
	.Clicked:Connect(function(value [number])
		> When the user clicks somewhere on the slider this fires the clicked position
	.DragStart:Connect(function()
		> Fires when the user starts dragging the slider
	.DragStop:Connect(function()
		> Fires when the user stops dragging the slider
--]]

-- CONSTANTS

local GuiLib = script.Parent.Parent
local Lazy = require(GuiLib:WaitForChild("LazyLoader"))
local Defaults = GuiLib:WaitForChild("Defaults")

local UIS = game:GetService("UserInputService")
local RUNSERVICE = game:GetService("RunService")

local SLIDER_FRAMEX = Defaults:WaitForChild("SliderFrameX")
local SLIDER_FRAMEY = Defaults:WaitForChild("SliderFrameY")

local XBOX_STEP = 0.01
local DEBOUNCE_TICK = 0.1
local XBOX_DEADZONE = 0.35
local THUMBSTICK = Enum.KeyCode.Thumbstick2

-- Class

local SliderClass = {}
SliderClass.__index = SliderClass
SliderClass.__type = "Slider"

function SliderClass:__tostring()
	return SliderClass.__type
end

-- Public Constructors

function SliderClass.new(sliderFrame, axis)
	local self = setmetatable({}, SliderClass)
	
	self._Maid = Lazy.Utilities.Maid.new()
	self._Spring = Lazy.Utilities.Spring.new(1, 0.1, 1, 0)
	self._Axis = axis or "x"
	self._ChangedBind = Instance.new("BindableEvent")
	self._ClickedBind = Instance.new("BindableEvent")
	
	self.Interval = 0
	self.IsActive = true
	self.TweenClick = true
	self.Inverted = false
	
	self.Frame = sliderFrame
	self.Changed = self._ChangedBind.Event
	self.Clicked = self._ClickedBind.Event
	self.DragStart = nil
	self.DragStop = nil
	
	init(self)
	self:Set(0.5)
	
	return self
end

function SliderClass.Create(axis)
	local slider = nil
	
	if (not axis or axis == "x") then
		slider = SliderClass.new(SLIDER_FRAMEX:Clone(), axis)
	else
		slider = SliderClass.new(SLIDER_FRAMEY:Clone(), axis)
		slider.Inverted = true
	end
	
	return slider
end

-- Private Methods

function init(self)
	local frame = self.Frame
	local dragger = frame.Dragger
	local background = frame.Background
	
	local axis = self._Axis
	local maid = self._Maid
	local spring = self._Spring
	local dragTracker = Lazy.Classes.Dragger.new(dragger)
	
	self.DragStart = dragTracker.DragStart
	self.DragStop = dragTracker.DragStop
	
	maid:Mark(frame)
	maid:Mark(self._ChangedBind)
	maid:Mark(self._ClickedBind)
	maid:Mark(function() dragTracker:Destroy() end)
	
	-- Get bounds and background size scaled accordingly for calculations
	local function setUdim2(a, b)
		if (axis == "y") then a, b = b, a end
		return UDim2.new(a, 0, b, 0)
	end
	
	local last = -1
	local bPos, bSize
	local initialBoundsCalculated = false
	local function updateBounds()
		bPos, bSize = getBounds(self)
		background.Size = setUdim2(bSize / frame.AbsoluteSize[axis], 1)
		last = -1
	end
	
	maid:Mark(frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateBounds))
	maid:Mark(frame:GetPropertyChangedSignal("AbsolutePosition"):Connect(updateBounds))
	maid:Mark(frame:GetPropertyChangedSignal("Parent"):Connect(updateBounds))
	
	-- Move the slider when the xbox moves it
	local xboxDir = 0
	local xboxTick = 0
	local xboxSelected = false
	
	maid:Mark(dragger.SelectionGained:Connect(function()
		xboxSelected = true
	end))
	
	maid:Mark(dragger.SelectionLost:Connect(function()
		xboxSelected = false
	end))
	
	maid:Mark(UIS.InputChanged:Connect(function(input, process)
		if (process and input.KeyCode == THUMBSTICK) then
			local pos = input.Position
			xboxDir = math.abs(pos[axis]) > XBOX_DEADZONE and math.sign(pos[axis]) or 0
		end
	end))
	
	-- Move the slider when we drag it
	maid:Mark(dragTracker.DragChanged:Connect(function(element, input, delta)
		if (self.IsActive) then
			self:Set((input.Position[axis] - bPos) / bSize, false)
		end
	end))
	
	-- Move the slider when we click somewhere on the bar
	maid:Mark(frame.InputBegan:Connect(function(input)
		if (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
			local t = (input.Position[axis] - bPos) / bSize
			self._ClickedBind:Fire(math.clamp(t, 0, 1))
			if (self.IsActive) then
				self:Set(t, self.TweenClick)
			end
		end
	end))
	
	-- position the slider
	maid:Mark(RUNSERVICE.RenderStepped:Connect(function(dt)
		if not initialBoundsCalculated then
			-- update on first rendered frame to make sure absolute sizes are correct
			updateBounds()
			initialBoundsCalculated = true
		end

		if (xboxSelected) then
			local t = tick()
			if (self.Interval <= 0) then
				self:Set(self:Get() + xboxDir*XBOX_STEP*dt*60)
			elseif (t - xboxTick > DEBOUNCE_TICK) then
				xboxTick = t
				self:Set(self:Get() + self.Interval*xboxDir)
			end
		end
		
		spring:Update(dt)
		local x = spring.x
		if (x ~= last) then
			local aPos = frame.AbsolutePosition[axis]
			local aSize = frame.AbsoluteSize[axis]
			local scalePos = (bPos + (x * bSize) - aPos) / aSize
			dragger.Position = setUdim2(scalePos, 0.5)
			self._ChangedBind:Fire(self:Get())
			last = x
		end
	end))
end

function getBounds(self)
	local frame = self.Frame
	local dragger = frame.Dragger
	local axis = self._Axis
	
	local pos = frame.AbsolutePosition[axis] + dragger.AbsoluteSize[axis]/2
	local size = frame.AbsoluteSize[axis] - dragger.AbsoluteSize[axis]
	
	return pos, size
end

-- Public Methods

function SliderClass:Get()
	local t = self._Spring.x
	if (self.Inverted) then t = 1 - t end
	return t
end

function SliderClass:Set(value, doTween)
	local spring = self._Spring
	local newT = math.clamp(value, 0, 1)
	
	if (self.Interval > 0) then
		newT = math.floor((newT / self.Interval) + 0.5) * self.Interval
	end
	
	spring.t = newT
	spring.instant = not doTween
end

function SliderClass:Destroy()
	self._Maid:Sweep()
	self.Frame:Destroy()
	self.Changed = nil
	self.Clicked = nil
	self.StartDrag = nil
	self.StopDrag = nil
	self.Frame = nil
end

--

return SliderClass