UI Slider

From GiderosMobile
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Here you will find various resources to help you create sliders in Gideros Studio.

note: You may have to provide your own assets (fonts, gfx, …)

Slider

-- UI Slider class
Slider = Core.class(Sprite)

function Slider:init(slit, knob)
	self.slit = slit
	self.width = self.slit:getWidth()
	self:addChild(self.slit)

	self.knob = knob
	self:addChild(self.knob)

	self.value = 0
	self.isFocus = false

	self:addEventListener(Event.MOUSE_DOWN, self.onMouseDown, self)
	self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self)
	self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)
end

function Slider:onMouseDown(event)
	if self.knob:hitTestPoint(event.x, event.y) then
		self.isFocus = true
		self.x0 = event.x
		event:stopPropagation()
	end
end

function Slider:onMouseMove(event)
	if self.isFocus then
		local dx = event.x - self.x0
		self.knob:setX(self.knob:getX() + dx)
		self.x0 = event.x
		
		-- keep the knob position within its range
		if self.knob:getX() < 0 then self.knob:setX(0) end
		if self.knob:getX() > self.width then self.knob:setX(self.width) end
		self.value = math.floor(100 * self.knob:getX() / self.width)
		event:stopPropagation()
	end
end

function Slider:onMouseUp(event)
	if self.isFocus then
		self.isFocus = false
		event:stopPropagation()
	end
end

function Slider:setValue(value)
	local value = math.floor(value)
	-- check within a range of [0, 100]
	if value < 0 then value = 0 end
	if value > 100 then value = 100 end
	local posX = self.width * value / 100
	self.knob:setPosition(posX, 0)
	self.value = value
end

function Slider:getValue()
	return self.value
end

---- USAGE
--local slit = Bitmap.new(Texture.new("Images/slit.png"))
--slit:setAnchorPoint(0, 0.5)
--local knob = Bitmap.new(Texture.new("Images/knob.png"))
--knob:setAnchorPoint(0.5, 0.5)
--local myslider = Slider.new(slit, knob)
--stage:addChild(myslider)
--slider:setValue(75)

Another Slider

You can rotate it as well (0 and 90° work best)

--[[
-- ASlider
-- mokalux, cc0
-- Slith, Knob, steps, text, ...
v 0.0.1: 2024-04-23 my take on a ui slider
]]

-- Class
ASlider = Core.class(Sprite) -- integers only slider

local floor = math.floor

function ASlider:init(xparams)
	local params = xparams or {}
	params.initialvalue = xparams.initialvalue or 0
	params.maximum = xparams.maximum or 100
	params.steps = xparams.steps or params.maximum
	params.slitcolor = xparams.slitcolor or 0x0
	params.slitalpha = xparams.slitalpha or 1
	params.slitw = xparams.slitw or 64
	params.slith = xparams.slith or 64
	params.knobcolor = xparams.knobcolor or 0xffffff
	params.knobalpha = xparams.knobalpha or 1
	params.knobw = xparams.knobw or 32
	params.knobh = xparams.knobh or 32
	params.text = xparams.text or nil
	params.font = xparams.font or nil
	params.textscale = xparams.textscale or 1
	params.textcolor = xparams.textcolor or 0xffffff
	params.textoffsetx = xparams.textoffsetx or 0
	params.textoffsety = xparams.textoffsety or 0
	params.textrotation = xparams.textrotation or 0
	params.id = xparams.id or nil
	-- slit and knob
	self.slit = Pixel.new(params.slitcolor, params.slitalpha, params.slitw, params.slith)
	self.slit:setAnchorPoint(0, 0.5)
	self.knob = Pixel.new(params.knobcolor, params.knobalpha, params.knobw, params.knobh)
	self.knob:setAnchorPoint(0.5, 0.5)
	-- textfield
	self.textfield = TextField.new(params.font, params.text or params.maximum) -- if no text then maximum
	self.textfield:setRotation(params.textrotation)
	self.textfield:setScale(params.textscale)
	self.textfield:setTextColor(params.textcolor)
	-- position
	self.textfield:setPosition(self.slit:getX() + params.textoffsetx, self.slit:getY() + params.textoffsety)
	-- order
	self:addChild(self.slit)
	self:addChild(self.knob)
	self:addChild(self.textfield)
	-- class variables
	self.value = params.initialvalue
	self.maximum = params.maximum
	self.steps = params.steps
	self.width = self.slit:getWidth()
	self.text = params.text
	self.isFocus = false
	self.id = params.id
	-- let's go!
	self:setValue(self.value)
	-- event listeners
	self:addEventListener(Event.MOUSE_DOWN, self.onMouseDown, self)
	self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self)
	self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)
end

-- helper function
function ASlider:setRange(x, xstep)
	for s = 0, self.width do
		if x <= 0 + (self.width / xstep)/2 then
			return 0
		elseif x >= s * self.width / xstep and x <= (s + 1) * self.width / xstep - (self.width / xstep)/2 then
			return s * self.width / xstep
		elseif x >= (s + 1) * self.width / xstep - (self.width / xstep)/2 and x <= (s + 1) * self.width / xstep then
			return (s + 1) * self.width / xstep
		elseif x >= self.width - (self.width / xstep)/2 then
			return self.width
		end
	end
end

-- events
function ASlider:onMouseDown(event)
	if self.slit:hitTestPoint(event.x, event.y) or self.knob:hitTestPoint(event.x, event.y) then
		local function round(val, n)
			if (n) then return floor( (val * 10^n)+0.5 ) / (10^n) 
			else return floor(val+0.5)
			end
		end
		local x, _y = self:globalToLocal(event.x, event.y)
		self.isFocus = true
		self.knob:setX(self:setRange(x, self.steps))
		self.value = round(self.maximum * self.knob:getX() / self.width, 3)
		local e = Event.new("value_just_changed")
		e.value = self.value
		e.id = self.id
		self:dispatchEvent(e)
		event:stopPropagation()
	end
end

function ASlider:onMouseMove(event)
	if self.isFocus then
		local function round(val, n)
			if (n) then return floor( (val * 10^n)+0.5 ) / (10^n)
			else return floor(val+0.5)
			end
		end
		local x, _y = self:globalToLocal(event.x, event.y)
		self.knob:setX(self:setRange(x, self.steps))
		self.value = round(self.maximum * self.knob:getX() / self.width, 3)
		local e = Event.new("value_changing")
		e.value = self.value
		e.id = self.id
		self:dispatchEvent(e)
		event:stopPropagation()
	end
end

function ASlider:onMouseUp(event)
	if self.isFocus then
		self.isFocus = false
		local e = Event.new("value_changed")
		e.value = self.value
		e.id = self.id
		self:dispatchEvent(e)
		event:stopPropagation()
	end
end

-- function
function ASlider:setValue(xvalue)
	-- check within range [0, max]
	if xvalue < 0 then xvalue = 0 end
	if xvalue > self.maximum then xvalue = self.maximum end
	local posX = self.width * xvalue / self.maximum
	self.knob:setPosition(posX, 0)
	self.value = xvalue
	if self.text then self.textfield:setText(self.text.."\e[color=#ddc]"..self.value.."\e[color]") -- value is themed ;-)
	else self.textfield:setText("\e[color=#ddc]"..self.value.."\e[color]") -- value is themed ;-)
	end
end

--[[
---- usage: a complete scene example
Options = Core.class(Sprite)

function Options:init()
	-- bg
	application:setBackgroundColor(0x232a35)
	-- global var
	g_bgmvolume = 10
	g_difficulty = 1
	-- SLIDERS
	local slitcolor, knobcolor = 0x3a1d20, 0x8d595d
	self.bgmvolumeslider = ASlider.new({
		initialvalue=g_bgmvolume, maximum=100, --steps=2,
		slitcolor=slitcolor, slitalpha=1, slitw=5*myappwidth/10, slith=24,
		knobcolor=knobcolor, knobalpha=0.6, knobw=12, knobh=26,
		text="BGM VOLUME: ", textscale=2, textoffsetx=-26*8, textoffsety=7,
		id=1,
	})
	self.difficultyslider = ASlider.new({
		initialvalue=g_difficulty, maximum=2, --steps=2,
		slitcolor=slitcolor, slitalpha=1, slitw=5*myappwidth/10, slith=24,
		knobcolor=knobcolor, knobalpha=0.6, knobw=12, knobh=26,
		text="DIFFICULTY: ", textscale=2, textoffsetx=-26*8, textoffsety=7, textrotation=0,
		id=3,
	})
	-- position
	self.bgmvolumeslider:setPosition(29*8, 2.5*myappheight/10)
	self.difficultyslider:setPosition(29*8, 4.5*myappheight/10)
	-- order
	self:addChild(self.bgmvolumeslider)
	self:addChild(self.difficultyslider)
	-- sliders listeners
	self.bgmvolumeslider:addEventListener("value_just_changed", self.onValueJustChanged, self)
	self.bgmvolumeslider:addEventListener("value_changing", self.onValueChanging, self)
	self.bgmvolumeslider:addEventListener("value_changed", self.onValueChanged, self)
	self.difficultyslider:addEventListener("value_just_changed", self.onValueJustChanged, self)
	self.difficultyslider:addEventListener("value_changing", self.onValueChanging, self)
	self.difficultyslider:addEventListener("value_changed", self.onValueChanged, self)
	-- let's go!
	self:difficulty(g_difficulty)
	-- scenes listeners
	self:addEventListener("enterBegin", self.onTransitionInBegin, self)
	self:addEventListener("enterEnd", self.onTransitionInEnd, self)
	self:addEventListener("exitBegin", self.onTransitionOutBegin, self)
	self:addEventListener("exitEnd", self.onTransitionOutEnd, self)
end

-- sliders
function Options:difficulty(x)
	if x >= 2 then self.difficultyslider.textfield:setText("DIFFICULTY: \e[color=#ddc]HARD\e[color]")
	elseif x >= 1 then self.difficultyslider.textfield:setText("DIFFICULTY: \e[color=#ddc]MEDIUM\e[color]")
	else self.difficultyslider.textfield:setText("DIFFICULTY: \e[color=#ddc]EASY\e[color]")
	end
end
function Options:onValueJustChanged(e)
	if e.id == 1 then
		g_bgmvolume = e.value -- keep actual value, change in setVolume()
		self.bgmvolumeslider:setValue(g_bgmvolume)
	elseif e.id == 3 then
		g_difficulty = e.value
		self:difficulty(g_difficulty)
	end
end
function Options:onValueChanging(e)
	if e.id == 1 then -- bgm volume
		g_bgmvolume = e.value -- keep actual value, change in setVolume()
		self.bgmvolumeslider:setValue(g_bgmvolume)
	elseif e.id == 3 then
		self:difficulty(e.value)
	end
end
function Options:onValueChanged(e)
	if e.id == 1 then
		g_bgmvolume = e.value -- keep actual value, change in setVolume()
		local audio = Sound.new("audio/sfx/sfx_wpn_laser4.wav") -- feedback
		local channel = audio:play()
		channel:setVolume(g_bgmvolume)
		self.bgmvolumeslider:setValue(g_bgmvolume)
	elseif e.id == 3 then
		g_difficulty = e.value
		self:difficulty(g_difficulty)
	end
--	mySavePrefs(g_configfilepath)
end

-- KEYS HANDLER
function Options:myKeysPressed()
	self:addEventListener(Event.KEY_DOWN, function(e)
		-- mobile and desktop
		if e.keyCode == KeyCode.BACK or e.keyCode == KeyCode.ESC then self:back() end
	end)
end

-- scene transitions
function Options:onTransitionInBegin() end
function Options:onTransitionInEnd() self:myKeysPressed() end
function Options:onTransitionOutBegin() self:removeAllListeners() end
function Options:onTransitionOutEnd() end

-- scenes navigation
function Options:back() scenemanager:changeScene("menu", 1, transitions[1], easings[2]) end