Difference between revisions of "UI Slider"
From GiderosMobile
(18 intermediate revisions by 2 users 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 === | ||
− | < | + | <syntaxhighlight lang="lua"> |
-- UI Slider class | -- UI Slider class | ||
Slider = Core.class(Sprite) | Slider = Core.class(Sprite) | ||
Line 59: | Line 59: | ||
if value < 0 then value = 0 end | if value < 0 then value = 0 end | ||
if value > 100 then value = 100 end | if value > 100 then value = 100 end | ||
− | posX = self.width * value / 100 | + | local posX = self.width * value / 100 |
self.knob:setPosition(posX, 0) | self.knob:setPosition(posX, 0) | ||
self.value = value | self.value = value | ||
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)''' | |
− | |||
− | function | + | '''You can rotate it as well (0 and 90° work best)''' |
+ | <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 ASlider:init(xparams) | ||
local params = xparams or {} | local params = xparams or {} | ||
+ | params.initialvalue = xparams.initialvalue or 0 | ||
params.maximum = xparams.maximum or 100 | params.maximum = xparams.maximum or 100 | ||
+ | params.steps = xparams.steps or params.maximum | ||
params.slitcolor = xparams.slitcolor or 0x0 | params.slitcolor = xparams.slitcolor or 0x0 | ||
params.slitalpha = xparams.slitalpha or 1 | params.slitalpha = xparams.slitalpha or 1 | ||
Line 93: | Line 108: | ||
params.knobw = xparams.knobw or 32 | params.knobw = xparams.knobw or 32 | ||
params.knobh = xparams.knobh or 32 | params.knobh = xparams.knobh or 32 | ||
− | -- | + | params.text = xparams.text or nil |
− | + | params.font = xparams.font or nil | |
− | slit:setAnchorPoint(0, 0.5) | + | params.textscale = xparams.textscale or 1 |
− | + | params.textcolor = xparams.textcolor or 0xffffff | |
− | knob:setAnchorPoint(0.5, 0.5) | + | params.textoffsetx = xparams.textoffsetx or 0 |
− | -- | + | params.textoffsety = xparams.textoffsety or 0 |
− | self. | + | params.textrotation = xparams.textrotation or 0 |
− | self: | + | params.id = xparams.id or nil |
− | self. | + | -- 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.knob) | ||
− | -- | + | self:addChild(self.textfield) |
+ | -- class variables | ||
+ | self.value = params.initialvalue | ||
self.maximum = params.maximum | self.maximum = params.maximum | ||
− | self. | + | self.steps = params.steps |
+ | self.width = self.slit:getWidth() | ||
+ | self.text = params.text | ||
self.isFocus = false | 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_DOWN, self.onMouseDown, self) | ||
self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self) | self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self) | ||
Line 113: | Line 148: | ||
end | end | ||
− | function | + | -- helper function |
− | if self.knob:hitTestPoint(event.x, event.y) then | + | 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.isFocus = true | ||
− | self. | + | 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() | event:stopPropagation() | ||
end | end | ||
end | end | ||
− | function | + | function ASlider:onMouseMove(event) |
if self.isFocus then | if self.isFocus then | ||
− | local | + | 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 = self.maximum * self.knob:getX() / self.width | + | self.value = round(self.maximum * self.knob:getX() / self.width, 3) |
− | + | local e = Event.new("value_changing") | |
− | local e = Event.new(" | ||
e.value = self.value | e.value = self.value | ||
+ | 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") | local e = Event.new("value_changed") | ||
e.value = self.value | e.value = self.value | ||
+ | e.id = self.id | ||
self:dispatchEvent(e) | self:dispatchEvent(e) | ||
− | |||
event:stopPropagation() | event:stopPropagation() | ||
end | end | ||
end | end | ||
− | function | + | -- function |
− | + | function ASlider:setValue(xvalue) | |
− | -- check within | + | -- check within range [0, max] |
− | if | + | if xvalue < 0 then xvalue = 0 end |
− | if | + | if xvalue > self.maximum then xvalue = self.maximum end |
− | posX = self.width * | + | local posX = self.width * xvalue / self.maximum |
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 | ||
+ | </syntaxhighlight > | ||
+ | |||
+ | '''Example''' | ||
+ | <syntaxhighlight lang="lua"> | ||
+ | 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 | 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 | 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