local x=script.Parent.Parent local C=require(x:WaitForChild("\076\097\122\121\076\111\097\100\101\114"))local I=game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")local N=game:GetService("\082\117\110\083\101\114\118\105\099\101")local X=.01 local a=.1 local O=.35 local q=Enum.KeyCode.Thumbstick2 local c={}c.__index=c c.__type="\083\108\105\100\101\114"function c.__tostring(x)return c.__type end function c.new(x,I)local N=setmetatable({},c)N._Maid=C.Utilities.Maid.new()N._Spring=C.Utilities.Spring.new(1,.1,1,0)N._Axis=I or"\120"N._ChangedBind=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")N._ClickedBind=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")N.Interval=0 N.IsActive=true N.TweenClick=true N.Inverted=false N.Frame=x N.Changed=N._ChangedBind.Event N.Clicked=N._ClickedBind.Event N.DragStart=nil N.DragStop=nil init(N)N:Set(.5)return N end function init(x)local c=x.Frame local i=c.Dragger local T=c.Background local h=x._Axis local V=x._Maid local Z=x._Spring local F=C.Classes.Dragger.new(c)x.DragStart=F.DragStart x.DragStop=F.DragStop V:Mark(x._ChangedBind)V:Mark(x._ClickedBind)V:Mark(function()F:Destroy()end)local function y(x,C)if h=="\121"then x,C=C,x end return UDim2.new(x,0,C,0)end local s=-1 local L,U local function r()L,U=getBounds(x)T.Size=y(U/c.AbsoluteSize[h],1)s=-1 end r()V:Mark((c:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\083\105\122\101")):Connect(r))V:Mark((c:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\080\111\115\105\116\105\111\110")):Connect(r))V:Mark((c:GetPropertyChangedSignal("\080\097\114\101\110\116")):Connect(r))local J=0 local D=0 local p=false V:Mark(c.SelectionGained:Connect(function()p=true end))V:Mark(c.SelectionLost:Connect(function()p=false end))V:Mark(I.InputChanged:Connect(function(x,C)if C and x.KeyCode==q then local C=x.Position J=math.abs(C[h])>O and math.sign(C[h])or 0 end end))V:Mark(F.DragChanged:Connect(function(C,I,N)if x.IsActive then x:Set((I.Position[h]-L)/U,false)end end))V:Mark(c.InputBegan:Connect(function(C)if C.UserInputType==Enum.UserInputType.MouseButton1 or C.UserInputType==Enum.UserInputType.Touch then local I=(C.Position[h]-L)/U x._ClickedBind:Fire(math.clamp(I,0,1))if x.IsActive then x:Set(I,x.TweenClick)end end end))V:Mark(N.RenderStepped:Connect(function(C)if p then local I=tick()if x.Interval<=0 then x:Set(x:Get()+((J*X)*C)*60)elseif I-D>a then D=I x:Set(x:Get()+x.Interval*J)end end Z:Update(C)local I=Z.x if I~=s then local C=((L+I*U)-c.AbsolutePosition[h])/c.AbsoluteSize[h]i.Position=y(C,.5)x._ChangedBind:Fire(x:Get())s=I end end))end function getBounds(x)local C=x.Frame local I=C.Dragger local N=x._Axis local X=C.AbsolutePosition[N]+I.AbsoluteSize[N]/2 local a=C.AbsoluteSize[N]-I.AbsoluteSize[N]return X,a end function c.Get(x)local C=x._Spring.x if x.Inverted then C=1-C end return C end function c.Set(I,x,C)local N=I._Spring local X=math.clamp(x,0,1)if I.Interval>0 then X=math.floor(X/I.Interval+.5)*I.Interval end N.t=X N.instant=not C end function c.Destroy(x)x._Maid:Sweep()x.Changed=nil x.Clicked=nil x.StartDrag=nil x.StopDrag=nil x.Frame=nil end return c
--[[
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(frame)
	
	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(frame.SelectionGained:Connect(function()
		xboxSelected = true
	end))
	
	maid:Mark(frame.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