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)

Slider with Increments

Slider2 = Core.class(Sprite)

function Slider2:init(xparams)
	local params = xparams or {}
	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
	-- parametrable slit and knob
	local slit = Pixel.new(params.slitcolor, params.slitalpha, params.slitw, params.slith)
	slit:setAnchorPoint(0, 0.5)
	local knob = Pixel.new(params.knobcolor, params.knobalpha, params.knobw, params.knobh)
	knob:setAnchorPoint(0.5, 0.5)
	-- order
	self.width = slit:getWidth()
	self:addChild(slit)
	self.knob = knob
	self:addChild(self.knob)
	-- class variables
	self.maximum = params.maximum
	self.steps = params.steps
	self.value = 0
	self.isFocus = false
	-- 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

-- events
function Slider2:onMouseDown(event)
	if self:hitTestPoint(event.x, event.y) then
		local x, y = self:globalToLocal(event.x, event.y)
		self.isFocus = true
		self.knob:setX(self:setRange(x, self.steps))

		self.value = self:round(self.maximum * self.knob:getX() / self.width)
		local e = Event.new("value_changed")
		e.value = self.value
		self:dispatchEvent(e)

		event:stopPropagation()
	end
end

function Slider2:onMouseMove(event)
	if self.isFocus then
		local x, y = self:globalToLocal(event.x, event.y)
		self.knob:setX(self:setRange(x, self.steps))

		self.value = self:round(self.maximum * self.knob:getX() / self.width)
		local e = Event.new("value_changed")
		e.value = self.value
		self:dispatchEvent(e)

		event:stopPropagation()
	end
end

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

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

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

function Slider2:round(num)
	return num + (2^52 + 2^51) - (2^52 + 2^51)
end

--[[
---- usage
-- bg
application:setBackgroundColor(0x333333)
-- a volume slider
local volumeslider = Slider2.new({
	maximum=20, steps=4,
	slitcolor=0x330033, slitalpha=1, slitw=512 - 64 * 2, slith=48,
	knobcolor=0xff00ff, knobalpha=0.7, knobw=40, knobh=30,
})
volumeslider:setValue(10)
tfsfxvolume = TextField.new(nil, "VOLUME: "..volumeslider.value)
tfsfxvolume:setScale(4)
tfsfxvolume:setTextColor(0xffffff)
-- positions
tfsfxvolume:setPosition(64, 128)
volumeslider:setPosition(64, 196)
-- order
stage:addChild(tfsfxvolume)
stage:addChild(volumeslider)
-- listeners
function onVolumeValueChanged(ev)
	tfsfxvolume:setText("VOLUME: "..ev.value)
	g_sfxvolume = ev.value
end
volumeslider:addEventListener("value_changed", onVolumeValueChanged)
]]

Slider with Text (Increments)

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

SliderText = Core.class(Sprite)

function SliderText: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)
	-- text
	self.textfield = TextField.new(params.font, params.text)
	self.textfield:setRotation(params.textrotation)
	self.textfield:setScale(params.textscale)
	self.textfield:setTextColor(params.textcolor)
	-- order
	self:addChild(self.slit)
	self:addChild(self.knob)
	self:addChild(self.textfield)
	-- positions
	self.textfield:setPosition(self.slit:getX() + params.textoffsetx, self.slit:getY() + params.textoffsety)
	-- 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!
	if self.text then self.textfield:setText(self.text..self.value) end
	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

-- events
function SliderText:onMouseDown(event)
--	if self:hitTestPoint(event.x, event.y) then
	if self.slit:hitTestPoint(event.x, event.y) or self.knob:hitTestPoint(event.x, event.y) then
		local x, y = self:globalToLocal(event.x, event.y)
		self.isFocus = true
		self.knob:setX(self:setRange(x, self.steps))

		self.value = self:round(self.maximum * self.knob:getX() / self.width)
		local e = Event.new("value_changed")
		e.value = self.value
		e.id = self.id
		self:dispatchEvent(e)

		if self.text then self.textfield:setText(self.text..self.value) end

		event:stopPropagation()
	end
end

function SliderText:onMouseMove(event)
	if self.isFocus then
		local x, y = self:globalToLocal(event.x, event.y)
		self.knob:setX(self:setRange(x, self.steps))

		self.value = self:round(self.maximum * self.knob:getX() / self.width)
		local e = Event.new("value_changed")
		e.value = self.value
		e.id = self.id
		self:dispatchEvent(e)

		if self.text then self.textfield:setText(self.text..self.value) end

		event:stopPropagation()
	end
end

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

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

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

function SliderText:round(num)
	return num + (2^52 + 2^51) - (2^52 + 2^51)
end

--[[
---- usage
application:setBackgroundColor(0x333333)
-- sliders
local sliderA = SliderText.new({
	initialvalue=2, maximum=10, -- steps=2,
	slitcolor=0x330033, slitalpha=1, slitw=256*1.5, slith=48,
	knobcolor=0xffff00, knobalpha=0.7, knobw=40, knobh=30,
	text="SLIDER A: ", textscale=3, textoffsetx=64*0.2, textoffsety=48, textrotation=30,
	id=1,
})
local sliderB = SliderText.new({
	initialvalue=15, maximum=100, steps=5,
	slitcolor=0x330033, slitalpha=1, slitw=256*1.5, slith=48,
	knobcolor=0xff00ff, knobalpha=0.7, knobw=40, knobh=30,
	text="SLIDER B: ", textscale=3, textoffsetx=64*0.2, textoffsety=48,
	id=2,
})
local sliderC = SliderText.new({
	initialvalue=1, maximum=2, --steps=5,
	slitcolor=0x330033, slitalpha=1, slitw=256*0.7, slith=48,
	knobcolor=0x00ffff, knobalpha=0.7, knobw=40, knobh=30,
	text=nil, textscale=3, textoffsetx=64*0.2, textoffsety=48, textrotation=90,
	id=3,
})
-- positions
sliderA:setPosition(64, 256*1.7)
sliderA:setRotation(-90)
sliderB:setPosition(64*2.5, 256*0.3)
sliderC:setPosition(64*6, 256*1.5)
sliderC:setRotation(-90)
-- order
stage:addChild(sliderA)
stage:addChild(sliderB)
stage:addChild(sliderC)
-- functions
function sliderCFunction(xvalue)
	if xvalue >= 2 then sliderC.textfield:setText("HARD")
	elseif xvalue >= 1 then sliderC.textfield:setText("MEDIUM")
	else sliderC.textfield:setText("EASY")
	end
end
-- let's go!
sliderCFunction(sliderC.value)
-- listeners
function onValueChanged(ev)
	if ev.id == 3 then sliderCFunction(ev.value)
	else print(ev.id, ev.value)
	end
end
sliderA:addEventListener("value_changed", onValueChanged)
sliderB:addEventListener("value_changed", onValueChanged)
sliderC:addEventListener("value_changed", onValueChanged)
]]