I meant to do this for a while but work and procrastination slowed me down. I had the trouble of not being able to accurately set the value on small sliders, to combat this I have created a slider that expands to give a much better accuracy. You can change the expand/contract animations by editing the easing in the tween functions. The relative mode makes it so the slider grip stays in the same place and moves the slider to compensate. Anyway here it is:
Slider = class()
function Slider:init(pos,width,sval,eval,val,...)
if ... then self.text = ... else self.text = "" end
self.val = val
self.eval = eval
self.sval = sval
self.pos = pos
if type(width) == "number" then
self.width = width
self.w = {w = width}
else
self.width = width.x
self.w = {w = width.x}
end
self.hold = nil
self.txtcol = color(0,255)
self.visible = true
self.tween = nil
self.res = 0
self.type = "slider"
self.info = nil
self.holding = nil
end
function Slider:setVisible(bool)
self.visible = bool
end
function Slider:textCol(col)
self.txtcol = col
end
function Slider:setRes(res)
self.res = res
end
function Slider:addZero() end
function Slider:draw()
if not self.visible then return end
local p,z,s,sv,ev,v = self.pos,self.width,self.w.w,self.sval,self.eval,self.val
local h = (s/z)
local ns = s/((ev-sv))
local hl = self.hold
if hl then
hl = hl
p = p + vec2((p.x-hl)*(h-1),0)
end
local tp = p-vec2((ns*(sv+ev)*0.5),0)+vec2(((s/(ev-sv)))*v,0)
pushStyle()
fill(50,h*70-70)
rect(-10,-10,WIDTH+20,HEIGHT+20)
lineCapMode(PROJECT)
strokeWidth(h*30)
stroke(0,h*70-70)
line(p.x-s/2,p.y,p.x+s/2,p.y)
lineCapMode(ROUND)
strokeWidth(8+h*3)
stroke(0,255)
line(p.x-s/2,p.y,p.x+s/2,p.y)
strokeWidth(7+h*3)
stroke(255,255)
line(p.x-s/2,p.y,p.x+s/2,p.y)
fill(255,255)
stroke(0,255)
strokeWidth(1)
ellipse(tp.x,tp.y,19+h*3)
fill(255*(h-1),255)
font("Marion-Bold")
fontSize(12)
text(math.floor((v)*(10^self.res))/(10^self.res),p.x,p.y-18-h*2)
textMode(CORNER)
text(self.text,p.x-s/2,p.y+10+h*2)
popStyle()
end
function Slider:toucht(t)
if not self.visible then return end
if self.holding then return true end
local p,s,z,sv,ev,v = self.pos,self.w.w,self.width,self.sval,self.eval,self.val
local ns = ((ev-sv)/v)/s
local h = (s/z)-1
local hl = self.hold
if hl then
hl = hl
p = p + vec2((p.x-hl)*(h),0)
end
--local tp = p-vec2(s/2,0)+vec2(((s/(ev-sv)))*v,0)
local tp = p-vec2((ns*(sv+ev)*0.5),0)+vec2(((s/(ev-sv)))*v,0)
if (t.x > p.x-s/2-h*20-20 and t.x < p.x+s/2+h*20+20
and t.y > p.y-10-h*7.5 and t.y < p.y+10+h*7.5) or vec2(t.x,t.y):dist(tp)<15+h*2 then
return true
end
return false
end
function Slider:getValue()
return self.val
end
function Slider:touched(t)
if not self.visible then return end
local p,z,s,sv,ev,v = self.pos,self.width,self.w.w,self.sval,self.eval,self.val
local ns = s/((ev-sv))
local h = (s/z)
local hl = self.hold
if hl then
hl = hl
p = p + vec2((p.x-hl)*(h-1),0)
end
local tp = p-vec2(s/2,0)+vec2(((s/(ev-sv)))*v,0)
local cp = p-vec2((ns*(sv+ev)*0.5),0)+vec2(((s/(ev-sv)))*v,0)
local np,val
if t.state == BEGAN and self:toucht(t) then
if not self.hold then
if self.tween then
tween.stop(self.tween)
end
self.hold = cp.x
self.tween = tween(0.5,self.w,{w = self.width*2},tween.easing.backInOut,function()
self.tween = nil
end)
end
self.holding = true
end
if t.state == MOVING and self.hold and not self.tween and self.holding then
np = t.x
np = np - (p.x-s/2)
val = ((ev-sv)/s)*np+sv
self.val = math.ceil(((clamp(val,sv,ev)-0.5)*(10^self.res)))/(10^self.res)
end
if t.state == ENDED then
self.holding = nil
if not self.tween then
self.tween = tween(0.25,self.w,{w = self.width},tween.easing.backOut,function()
self.hold = nil
self.tween = nil
end)
end
end
end
Edit: fixed a bug.
Edit2: fixed another bug. Should work properly now.