114 lines
3.2 KiB
Lua
114 lines
3.2 KiB
Lua
--- 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
|