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