Difference between revisions of "UI Slider"
From GiderosMobile
m (Text replacement - "<source" to "<syntaxhighlight")  | 
				|||
| (5 intermediate revisions by the same user not shown) | |||
| Line 2: | Line 2: | ||
Here you will find various resources to help you create sliders in Gideros Studio.  | 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, …)  | + | '''note''': You may have to provide your own assets (fonts, gfx, …)  | 
=== Slider ===  | === Slider ===  | ||
| Line 76: | Line 76: | ||
--stage:addChild(myslider)  | --stage:addChild(myslider)  | ||
--slider:setValue(75)  | --slider:setValue(75)  | ||
| − | </  | + | </syntaxhighlight >  | 
| − | === Slider   | + | === Another Slider ===  | 
| + | You can download the ASlider Class here: '''[[Media:Aslider.lua]] (tip: right click and save link as)'''  | ||
| + | |||
| + | '''You can rotate it as well (0 and 90° work best)'''  | ||
<syntaxhighlight lang="lua">  | <syntaxhighlight lang="lua">  | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
--[[  | --[[  | ||
| − | --  | + | -- 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   | + | function ASlider:init(xparams)  | 
	local params = xparams or {}  | 	local params = xparams or {}  | ||
	params.initialvalue = xparams.initialvalue or 0  | 	params.initialvalue = xparams.initialvalue or 0  | ||
| Line 239: | Line 121: | ||
	self.knob = Pixel.new(params.knobcolor, params.knobalpha, params.knobw, params.knobh)  | 	self.knob = Pixel.new(params.knobcolor, params.knobalpha, params.knobw, params.knobh)  | ||
	self.knob:setAnchorPoint(0.5, 0.5)  | 	self.knob:setAnchorPoint(0.5, 0.5)  | ||
| − | 	--   | + | 	-- textfield  | 
| − | 	self.textfield = TextField.new(params.font, params.text)  | + | 	self.textfield = TextField.new(params.font, params.text or params.maximum) -- if no text then maximum  | 
	self.textfield:setRotation(params.textrotation)  | 	self.textfield:setRotation(params.textrotation)  | ||
	self.textfield:setScale(params.textscale)  | 	self.textfield:setScale(params.textscale)  | ||
	self.textfield:setTextColor(params.textcolor)  | 	self.textfield:setTextColor(params.textcolor)  | ||
| + | 	-- position  | ||
| + | 	self.textfield:setPosition(self.slit:getX() + params.textoffsetx, self.slit:getY() + params.textoffsety)  | ||
	-- order  | 	-- order  | ||
	self:addChild(self.slit)  | 	self:addChild(self.slit)  | ||
	self:addChild(self.knob)  | 	self:addChild(self.knob)  | ||
	self:addChild(self.textfield)  | 	self:addChild(self.textfield)  | ||
| − | |||
| − | |||
	-- class variables  | 	-- class variables  | ||
	self.value = params.initialvalue  | 	self.value = params.initialvalue  | ||
| Line 259: | Line 141: | ||
	self.id = params.id  | 	self.id = params.id  | ||
	-- let's go!  | 	-- let's go!  | ||
| − | |||
	self:setValue(self.value)  | 	self:setValue(self.value)  | ||
	-- event listeners  | 	-- event listeners  | ||
| Line 265: | Line 146: | ||
	self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self)  | 	self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self)  | ||
	self:addEventListener(Event.MOUSE_UP, self.onMouseUp, 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  | end  | ||
-- events  | -- events  | ||
| − | function   | + | function ASlider:onMouseDown(event)  | 
| − | |||
	if self.slit:hitTestPoint(event.x, event.y) or self.knob: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,   | + | 		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.isFocus = true  | ||
		self.knob:setX(self:setRange(x, self.steps))  | 		self.knob:setX(self:setRange(x, self.steps))  | ||
| − | + | 		self.value = round(self.maximum * self.knob:getX() / self.width, 3)  | |
| − | 		self.value =   | + | 		local e = Event.new("value_just_changed")  | 
| − | 		local e = Event.new("  | ||
		e.value = self.value  | 		e.value = self.value  | ||
		e.id = self.id  | 		e.id = self.id  | ||
		self:dispatchEvent(e)  | 		self:dispatchEvent(e)  | ||
| − | |||
| − | |||
| − | |||
		event:stopPropagation()  | 		event:stopPropagation()  | ||
	end  | 	end  | ||
end  | end  | ||
| − | function   | + | function ASlider:onMouseMove(event)  | 
	if self.isFocus then  | 	if self.isFocus then  | ||
| − | 		local x,   | + | 		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.knob:setX(self:setRange(x, self.steps))  | ||
| − | + | 		self.value = round(self.maximum * self.knob:getX() / self.width, 3)  | |
| − | 		self.value =   | + | 		local e = Event.new("value_changing")  | 
| − | 		local e = Event.new("  | ||
		e.value = self.value  | 		e.value = self.value  | ||
		e.id = self.id  | 		e.id = self.id  | ||
		self:dispatchEvent(e)  | 		self:dispatchEvent(e)  | ||
| − | |||
| − | |||
| − | |||
		event:stopPropagation()  | 		event:stopPropagation()  | ||
	end  | 	end  | ||
end  | end  | ||
| − | function   | + | function ASlider:onMouseUp(event)  | 
	if self.isFocus then  | 	if self.isFocus then  | ||
		self.isFocus = false  | 		self.isFocus = false  | ||
| + | 		local e = Event.new("value_changed")  | ||
| + | 		e.value = self.value  | ||
| + | 		e.id = self.id  | ||
| + | 		self:dispatchEvent(e)  | ||
		event:stopPropagation()  | 		event:stopPropagation()  | ||
	end  | 	end  | ||
end  | end  | ||
| − | --   | + | -- function  | 
| − | function   | + | function ASlider:setValue(xvalue)  | 
| − | + | 	-- check within range [0, max]  | |
| − | + | 	if xvalue < 0 then xvalue = 0 end  | |
| − | 	-- check within   | + | 	if xvalue > self.maximum then xvalue = self.maximum end  | 
| − | 	if   | + | 	local posX = self.width * xvalue / self.maximum  | 
| − | 	if   | ||
| − | 	local posX = self.width *   | ||
	self.knob:setPosition(posX, 0)  | 	self.knob:setPosition(posX, 0)  | ||
| − | 	self.value = value  | + | 	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  | end  | ||
| + | </syntaxhighlight >  | ||
| − | + | '''Example'''  | |
| − | + | <syntaxhighlight lang="lua">  | |
| − | + | Options = Core.class(Sprite)  | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | function   | + | function Options:init()  | 
| − | + | 	-- 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)  | ||
end  | end  | ||
| − | |||
| − | |||
| − | |||
-- sliders  | -- 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]")  | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | 	if   | ||
| − | 	elseif   | ||
| − | 	else   | ||
	end  | 	end  | ||
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  | ||
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  | ||
| + | end  | ||
| + | </syntaxhighlight >  | ||
| + | |||
| + | |||
| + | {{GIDEROS IMPORTANT LINKS}}  | ||
Latest revision as of 10:58, 26 October 2024
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 download the ASlider Class here: Media:Aslider.lua (tip: right click and save link as)
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
Example
Options = Core.class(Sprite)
function Options:init()
	-- 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)
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
end