--- Implements a scrollable slider widget
--
-- @classmod yui.Slider
-- @copyright 2022, The DoubleFourteen Code Forge
-- @author Lorenzo Cogotti, Andrea Pasquini
--
-- Slider widget receives the following callbacks: @{yui.Widget.WidgetCallbacks|onEnter}(), @{yui.Widget.WidgetCallbacks|onChange}(), @{yui.Widget.WidgetCallbacks|onLeave}().
local BASE = ( ... ) : gsub ( ' slider$ ' , ' ' )
local Widget = require ( BASE .. ' widget ' )
local core = require ( BASE .. ' core ' )
local Slider = setmetatable ( {
__call = function ( cls , args ) return cls : new ( args ) end
} , Widget )
Slider.__index = Slider
--- Attributes accepted by the @{Slider} widget beyond the standard @{yui.Widget.WidgetAttributes|attributes}
-- and @{yui.Widget.WidgetCallbacks|callbacks}.
--
-- @field min (number) min value of the slider
-- @field max (number) max value of the slider
-- @field vertical (boolean) true for vertical slider, false or nil for horizontal slider
-- @field value (number) default value
-- @field step (number) number of slider's steps
-- @table SliderAttributes
--- Slider constructor
-- @param args (@{SliderAttributes}) widget attributes
function Slider : new ( args )
self = setmetatable ( args , self )
self.vertical = self.vertical or false
self.min = self.min or 0
self.max = self.max or 1
self.value = self.value or self.min
self.step = self.step or ( self.max - self.min ) / 10
return self
end
function Slider : onPointerInput ( px , py , _ , down )
self : grabFocus ( )
if not down then
return
end
local x , y , w , h = self.x , self.y , self.w , self.h
local fraction
if self.vertical then
fraction = math.min ( 1 , math.max ( 0 , ( y + h - py ) / h ) )
else
fraction = math.min ( 1 , math.max ( 0 , ( px - x ) / w ) )
end
local v = fraction * ( self.max - self.min ) + self.min
if v ~= self.value then
self.value = v
self : onChange ( v )
end
end
function Slider : onActionInput ( action )
local up = self.vertical and ' up ' or ' right '
local down = self.vertical and ' down ' or ' left '
local handled = false
if action [ up ] then
self.value = math.min ( self.max , self.value + self.step )
handled = true
elseif action [ down ] then
self.value = math.max ( self.min , self.value - self.step )
handled = true
end
if handled then
self : onChange ( self.value )
end
return handled
end
function Slider : draw ( )
local x , y , w , h = self.x , self.y , self.w , self.h
local r = math.min ( w , h ) / 2.1
local color , _ , cornerRadius = core.themeForWidget ( self )
local c = core.colorForWidgetState ( self , color )
local fraction = ( self.value - self.min ) / ( self.max - self.min )
local xb , yb , wb , hb -- size of the progress bar
if self.vertical then
x , w = x + w * .25 , w * .5
xb , yb , wb , hb = x , y + h * ( 1 - fraction ) , w , h * fraction
else
y , h = y + h * .25 , h * .5
xb , yb , wb , hb = x , y , w * fraction , h
end
core.drawBox ( x , y , w , h , c , cornerRadius )
core.drawBox ( xb , yb , wb , hb , { bg = c.fg } , cornerRadius )
if self : isFocused ( ) then
love.graphics . setColor ( c.fg )
if self.vertical then
love.graphics . circle ( ' fill ' , x + wb / 2 , yb , r )
else
love.graphics . circle ( ' fill ' , x + wb , yb + hb / 2 , r )
end
end
end
return Slider