Difference between revisions of "UI Buttons"

From GiderosMobile
(added another button UDDP)
(8 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
Here you will find various resources to help you create buttons in Gideros Studio.
 
Here you will find various resources to help you create buttons in Gideros Studio.
  
'''note''':You may have to provide your own assets (fonts, gfx, …).
+
'''note''': UDD = Up Down Disabled images.<br/>
 +
'''note2''': You may have to provide your own assets (fonts, gfx, …).
  
=== <translate>Simple Button</translate> ===
+
=== Simple Button ===
 
<source lang="lua">
 
<source lang="lua">
 
--[[
 
--[[
Line 125: Line 126:
 
</source>
 
</source>
  
 +
 +
=== Simple Text Button ===
 +
<source lang="lua">
 +
--[[
 +
ButtonTextBasic
 +
A simple Button class with a Pixel and/or text. Ideal for in game action.
 +
This code is CC0
 +
github: mokalux
 +
v 0.1.1: 2020-06-08 remove useless variables
 +
v 0.1.0: 2020-04-02 init (based on the initial gideros generic button class)
 +
]]
 +
--[[
 +
-- SAMPLES
 +
local mybtnquit = ButtonTextBasic.new({
 +
pixelcolorup=mypixelcolorup,
 +
text="X", font=g_font1, fontsize=32, textcolorup=mytextcolorup, textcolordown=mytextcolordown,
 +
})
 +
mybtnquit:setPosition(myappright - mybtnquit:getWidth() / 2, myapptop + mybtnquit:getHeight() / 2)
 +
self:addChild(mybtnquit)
 +
mybtnquit:addEventListener("clicked", function() self:goMenu() end)
 +
]]
 +
ButtonTextBasic = Core.class(Sprite)
 +
 +
function ButtonTextBasic:init(xparams)
 +
-- the params
 +
self.params = xparams or {}
 +
-- pixel?
 +
self.params.pixelcolorup = xparams.pixelcolorup or nil -- color
 +
self.params.pixelcolordown = xparams.pixelcolordown or self.params.pixelcolorup -- color
 +
self.params.pixelalpha = xparams.pixelalpha or 1 -- number
 +
self.params.pixelscalex = xparams.pixelscalex or 1 -- number
 +
self.params.pixelscaley = xparams.pixelscaley or 1 -- number
 +
self.params.pixelpaddingx = xparams.pixelpaddingx or 12 -- number
 +
self.params.pixelpaddingy = xparams.pixelpaddingy or 12 -- number
 +
-- text?
 +
self.params.text = xparams.text or nil -- string
 +
self.params.font = xparams.font or nil -- ttf font path
 +
self.params.fontsize = xparams.fontsize or 16 -- number
 +
self.params.textcolorup = xparams.textcolorup or 0x0 -- color
 +
self.params.textcolordown = xparams.textcolordown or self.params.textcolorup -- color
 +
self.params.textscalex = xparams.textscalex or 1 -- number
 +
self.params.textscaley = xparams.textscaley or self.params.textscalex -- number
 +
-- EXTRAS
 +
self.params.isautoscale = xparams.isautoscale or 1 -- number (default 1 = true)
 +
self.params.defaultpadding = xparams.defaultpadding or 12 -- number
 +
-- LET'S GO!
 +
if self.params.isautoscale == 0 then self.params.isautoscale = false else self.params.isautoscale = true end
 +
-- warnings
 +
if not self.params.pixelcolorup and not self.params.text then
 +
print("*** WARNING: YOUR BUTTON IS EMPTY! ***")
 +
else
 +
-- mouse catcher
 +
self.catcher = Pixel.new(0x0, 0, 1, 1)
 +
self:addChild(self.catcher)
 +
-- sprite holder
 +
self.sprite = Sprite.new()
 +
self:addChild(self.sprite)
 +
self:setButton()
 +
end
 +
-- update visual state
 +
self.focus = false
 +
self:updateVisualState(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
 +
 +
-- FUNCTIONS
 +
function ButtonTextBasic:setButton()
 +
-- text
 +
local textwidth, textheight
 +
if self.params.text then
 +
local font
 +
if self.params.font ~= nil then
 +
-- font = TTFont.new(self.params.font, self.params.fontsize, "", true, 1) -- filtering, outline (number)
 +
font = TTFont.new(self.params.font, self.params.fontsize, "")
 +
end
 +
if self.text ~= nil then
 +
self.text:setButton(self.params.text)
 +
else
 +
self.text = TextField.new(font, self.params.text, self.params.text)
 +
end
 +
self.text:setAnchorPoint(0.5, 0.5)
 +
self.text:setScale(self.params.textscalex, self.params.textscaley)
 +
self.text:setTextColor(self.params.textcolorup)
 +
textwidth, textheight = self.text:getWidth(), self.text:getHeight()
 +
end
 +
-- first add pixel
 +
if self.params.pixelcolorup then
 +
if self.params.isautoscale and self.params.text then
 +
self.pixel = Pixel.new(
 +
self.params.pixelcolor, self.params.pixelalpha,
 +
textwidth + self.params.pixelpaddingx,
 +
textheight + self.params.pixelpaddingy)
 +
else
 +
self.pixel = Pixel.new(
 +
self.params.pixelcolor, self.params.pixelalpha,
 +
self.params.pixelpaddingx,
 +
self.params.pixelpaddingy)
 +
end
 +
self.pixel:setAnchorPoint(0.5, 0.5)
 +
self.pixel:setScale(self.params.pixelscalex, self.params.pixelscaley)
 +
self.sprite:addChild(self.pixel)
 +
end
 +
-- finally add text on top of all
 +
if self.params.text then self.sprite:addChild(self.text) end
 +
-- mouse catcher
 +
self.catcher:setDimensions(self.sprite:getWidth() + 8 * 2.5, self.sprite:getHeight() + 8 * 2.5) -- magik
 +
self.catcher:setAnchorPoint(0.5, 0.5)
 +
end
 +
 +
-- VISUAL STATE
 +
function ButtonTextBasic:updateVisualState(xstate)
 +
if xstate then -- button down state
 +
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordown) end
 +
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordown) end
 +
else -- button up state
 +
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolorup) end
 +
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
 +
end
 +
end
 +
 +
-- MOUSE LISTENERS
 +
function ButtonTextBasic:onMouseDown(e)
 +
if self:hitTestPoint(e.x, e.y) then
 +
self.focus = true
 +
self:updateVisualState(true)
 +
e:stopPropagation()
 +
end
 +
end
 +
function ButtonTextBasic:onMouseMove(e)
 +
if self:hitTestPoint(e.x, e.y) then
 +
self.focus = true
 +
e:stopPropagation()
 +
else
 +
self.focus = false
 +
-- e:stopPropagation() -- you may want to delete this line
 +
end
 +
self:updateVisualState(self.focus)
 +
end
 +
function ButtonTextBasic:onMouseUp(e)
 +
if self.focus then
 +
self.focus = false
 +
self:dispatchEvent(Event.new("clicked")) -- button is clicked, dispatch "clicked" event
 +
e:stopPropagation()
 +
end
 +
end
 +
</source>
  
 
=== Button with an Up, Down and Disabled state (UDD) ===
 
=== Button with an Up, Down and Disabled state (UDD) ===
Line 270: Line 420:
  
 
=== Button with Text and/or Images ===
 
=== Button with Text and/or Images ===
 +
'''note''': You don't have to use an image, for example you can create a button with text only.
 
<source lang="lua">
 
<source lang="lua">
 
--[[
 
--[[
Line 482: Line 633:
  
 
=== Button with Text and/or Images UDD ===
 
=== Button with Text and/or Images UDD ===
'''This button has it all (almost) :-)'''
+
'''This button has it all (almost) :-)'''<br/>
 +
'''note''': You don't have to use all parameters (UDD), for example you can create a button with text only.
 
<source lang="lua">
 
<source lang="lua">
 
--[[
 
--[[
Line 756: Line 908:
  
  
=== Button with Text and/or Images UDDP ===
+
=== Button with Text, Pixel, Images 9 Patch, UDD, Tooltip ===
'''This button has it all :-)'''
+
'''This button is the most complete :-)'''<br/>
 +
'''note''': You don't have to use all parameters, for example you can create a button with text only.
 
<source lang="lua">
 
<source lang="lua">
 
--[[
 
--[[
A Button class with text and/or image/pixel with Up state, Down state, Disabled state (UDD)
+
ButtonTextP9UDDT
This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php
+
A Button class with text, Pixel, images 9patch (Up, Down, Disabled) and Tooltip
 +
This code is CC0
 
github: mokalux
 
github: mokalux
 +
v 0.1.5: 2020-08-25 replaced font params with ttf params for better control
 +
v 0.1.41: 2020-08-19 added tooltip text scale and color
 +
v 0.1.4: 2020-06-08 removed useless variables + the class was somehow broken :/
 +
v 0.1.3: 2020-03-30 added tooltiptext
 +
v 0.1.2: 2020-03-29 added nine patch
 +
v 0.1.1: 2020-03-28 added pixel
 
v 0.1.0: 2020-03-28 init (based on the initial gideros generic button class)
 
v 0.1.0: 2020-03-28 init (based on the initial gideros generic button class)
 
]]
 
]]
 
--[[
 
--[[
-- SAMPLES
+
-- SAMPLE
local button = ButtonTextUDDP.new({
+
-- BUTTON QUIT
imgup="gfx/ui/btn_01_up.png", imgdown="gfx/ui/btn_01_down.png",
+
local mybtnquit = ButtonTextP9UDDT.new({
text="BUTTON 1", textscalex=4, textcolorup=0x0, textcolordown=0xffff00,
+
pixelcolorup=0x0, pixelpaddingx=3, pixelpaddingy=3,
})
+
text="QUIT", ttf=mycompositefont,
local button2 = ButtonTextUDDP.new({
+
textcolorup=0xffffff, textcolordown=0xff00ff,
imgup="gfx/ui/btn_02_up.png", imgdown="gfx/ui/btn_02_down.png", imgdisabled="gfx/ui/btn_02_disabled.png",
+
hover=true,
text="BUTTON 2", textscalex=4, textcolorup=0x0, textcolordown=0xffff00, font = "fonts/Kenney Future Narrow.ttf", fontsize = 10,
+
})
nohover=true,
+
mybtnquit:setPosition(64, 64)
})
+
stage:addChild(mybtnquit)
button:addEventListener("clicked", function()
+
mybtnquit:addEventListener("clicked", function() self:goExit() end)
button2:setDisabled(not button2:isDisabled())
+
mybtnquit:setDisabled(true)
end)
 
button2:addEventListener("click", function()
 
-- your code here
 
end)
 
 
 
local button3 = ButtonTextUDDP.new({
 
pixelcolorup = "0xffddff", pixelcolordown = "0xff0000",
 
text = "BUTTON 3", textscalex = 4,
 
})
 
button:setPosition(2.25 * 64, 2 * 32)
 
button2:setPosition(2.25 * 64, 4.5 * 32)
 
button3:setPosition(2.25 * 64, 7 * 32)
 
stage:addChild(button)
 
stage:addChild(button2)
 
stage:addChild(button3)
 
 
]]
 
]]
ButtonTextUDDP = Core.class(Sprite)
+
ButtonTextP9UDDT = Core.class(Sprite)
  
function ButtonTextUDDP:init(xparams)
+
function ButtonTextP9UDDT:init(xparams)
-- the params
+
-- the params table
 
self.params = xparams or {}
 
self.params = xparams or {}
 +
-- pixel?
 +
self.params.pixelcolorup = xparams.pixelcolorup or nil -- color
 +
self.params.pixelcolordown = xparams.pixelcolordown or self.params.pixelcolorup -- color
 +
self.params.pixelcolordisabled = xparams.pixelcolordisabled or 0x555555 -- color
 +
self.params.pixelalpha = xparams.pixelalpha or 1 -- number
 +
self.params.pixelscalex = xparams.pixelscalex or 1 -- number
 +
self.params.pixelscaley = xparams.pixelscaley or 1 -- number
 +
self.params.pixelpaddingx = xparams.pixelpaddingx or 12 -- number
 +
self.params.pixelpaddingy = xparams.pixelpaddingy or 12 -- number
 
-- textures?
 
-- textures?
 
self.params.imgup = xparams.imgup or nil -- img up path
 
self.params.imgup = xparams.imgup or nil -- img up path
 
self.params.imgdown = xparams.imgdown or self.params.imgup -- img down path
 
self.params.imgdown = xparams.imgdown or self.params.imgup -- img down path
 
self.params.imgdisabled = xparams.imgdisabled or self.params.imgup -- img disabled path
 
self.params.imgdisabled = xparams.imgdisabled or self.params.imgup -- img disabled path
self.params.imgscalex = xparams.imgscalex or nil -- number or nil = autoscale
+
self.params.imagealpha = xparams.imagealpha or 1 -- number
self.params.imgscaley = xparams.imgscaley or nil -- number or nil = autoscale
+
self.params.imgscalex = xparams.imgscalex or 1 -- number
-- pixel?
+
self.params.imgscaley = xparams.imgscaley or 1 -- number
self.params.pixelcolorup = xparams.pixelcolorup or nil -- color
+
self.params.imagepaddingx = xparams.imagepaddingx or nil -- number (nil = auto, the image width)
self.params.pixelcolordown = xparams.pixelcolordown or self.params.pixelcolorup -- color
+
self.params.imagepaddingy = xparams.imagepaddingy or nil -- number (nil = auto, the image height)
self.params.pixelcolordisabled = xparams.pixelcolordisabled or 0x555555 -- color
 
self.params.pixelscalex = xparams.pixelscalex or nil -- number or nil = autoscale
 
self.params.pixelscaley = xparams.pixelscaley or nil -- number or nil = autoscale
 
 
-- text?
 
-- text?
 
self.params.text = xparams.text or nil -- string
 
self.params.text = xparams.text or nil -- string
self.params.font = xparams.font or nil -- ttf font path
+
self.params.ttf = xparams.ttf or nil -- ttf
self.params.fontsize = xparams.fontsize or 16 -- number
 
 
self.params.textcolorup = xparams.textcolorup or 0x0 -- color
 
self.params.textcolorup = xparams.textcolorup or 0x0 -- color
 
self.params.textcolordown = xparams.textcolordown or self.params.textcolorup -- color
 
self.params.textcolordown = xparams.textcolordown or self.params.textcolorup -- color
Line 820: Line 970:
 
self.params.textscalex = xparams.textscalex or 1 -- number
 
self.params.textscalex = xparams.textscalex or 1 -- number
 
self.params.textscaley = xparams.textscaley or self.params.textscalex -- number
 
self.params.textscaley = xparams.textscaley or self.params.textscalex -- number
self.params.nohover = xparams.nohover or nil -- boolean
+
-- EXTRAS
-- let's go
+
self.params.isautoscale = xparams.isautoscale or 1 -- number (default 1 = true)
self.sprite = Sprite.new()
+
self.params.hover = xparams.hover or 0 -- number (default 0 = false)
self.sprite:setAnchorPoint(0.5,0.5)
+
self.params.defaultpadding = xparams.defaultpadding or 12 -- number
self:addChild(self.sprite)
+
self.params.tooltiptext = xparams.tooltiptext or nil -- string
-- button has up state image?
+
self.params.tooltiptextscale = xparams.tooltiptextscale or 2
if self.params.imgup ~= nil then
+
self.params.tooltiptextcolor = xparams.tooltiptextcolor or 0x0
self.bmpup = Bitmap.new(Texture.new(self.params.imgup))
+
-- LET'S GO!
self.bmpup:setAnchorPoint(0.5, 0.5)
+
if self.params.isautoscale == 0 then self.params.isautoscale = false else self.params.isautoscale = true end
self.bmpupwidth = self.bmpup:getWidth()
+
if self.params.hover == 0 then self.params.hover = false else self.params.hover = true end
self.bmpupheight = self.bmpup:getHeight()
+
-- warnings
self.sprite:addChild(self.bmpup)
+
if not self.params.imgup and not self.params.imgdown and not self.params.imgdisabled
self.hasbmpup = true
+
and not self.params.pixelcolorup and not self.params.text and not self.params.tooltiptext then
 +
print("*** WARNING: YOUR BUTTON IS EMPTY! ***")
 
else
 
else
self.hasbmpup = false
+
-- draws a pixel around the button to catch the mouse leaving the button
end
+
self.catcher = Pixel.new(0x0, 0.25, 1, 1)
-- button has down state image?
+
self:addChild(self.catcher)
if self.params.imgdown ~= nil then
+
-- button sprite holder
self.bmpdown = Bitmap.new(Texture.new(self.params.imgdown))
+
self.sprite = Sprite.new()
self.bmpdown:setAnchorPoint(0.5, 0.5)
+
self:addChild(self.sprite)
self.bmpdownwidth = self.bmpdown:getWidth()
+
self:setButton()
self.bmpdownheight = self.bmpdown:getHeight()
 
self.sprite:addChild(self.bmpdown)
 
self.hasbmpdown = true
 
else
 
self.hasbmpdown = false
 
end
 
-- button has disabled state image?
 
if self.params.imgdisabled ~= nil then
 
self.bmpdisabled = Bitmap.new(Texture.new(self.params.imgdisabled))
 
self.bmpdisabled:setAnchorPoint(0.5, 0.5)
 
self.bmpdisabledwidth = self.bmpdown:getWidth()
 
self.bmpdisabledheight = self.bmpdown:getHeight()
 
self.sprite:addChild(self.bmpdisabled)
 
self.hasbmpdisabled = true
 
else
 
self.hasbmpdisabled = false
 
end
 
-- button has pixel?
 
if self.params.pixelcolorup ~= nil then
 
self.pixel = Pixel.new(self.params.pixelcolor, 1, 48, 48)
 
self.pixel:setAnchorPoint(0.5, 0.5)
 
self.pixel:setScale(self.params.pixelscalex or 1, self.params.pixelscaley or 1)
 
self.pixelwidth, self.pixelheight = self.pixel:getSize()
 
self.sprite:addChild(self.pixel)
 
self.haspixel = true
 
else
 
self.haspixel = false
 
end
 
-- button has text?
 
if self.params.text ~= nil then
 
self:setText(self.params.text)
 
self.hastext = true
 
else
 
self.hastext = false
 
end
 
-- warnings
 
if not self.hasbmpup and not self.hasbmpdown and not self.hasbmpdisabled and not self.haspixel and not self.hastext then
 
print("*** WARNING: BUTTON NEEDS AT LEAST A TEXTURE, A PIXEL OR SOME TEXT! ***")
 
 
end
 
end
 
-- update visual state
 
-- update visual state
Line 889: Line 1,002:
 
self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)
 
self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)
 
self:addEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
 
self:addEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
if self.params.nohover then
+
if not self.params.hover and not self.params.tooltiptext then
 
-- print("*** no mouse hover effect ***")
 
-- print("*** no mouse hover effect ***")
 
self:removeEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
 
self:removeEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
 
end
 
end
-- mobile
 
self:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
 
self:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
 
self:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
 
self:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
 
 
end
 
end
  
 
-- FUNCTIONS
 
-- FUNCTIONS
function ButtonTextUDDP:setText(xtext)
+
function ButtonTextP9UDDT:setButton()
if self.params.font ~= nil then
+
local textwidth, textheight
-- self.font = TTFont.new(self.params.font, self.params.fontsize, "", true, 1) -- , filtering, outline (number)
+
local bmps = {}
self.font = TTFont.new(self.params.font, self.params.fontsize, "")
+
-- text
 +
if self.params.text then
 +
self.text = TextField.new(self.params.ttf, self.params.text, self.params.text)
 +
self.text:setAnchorPoint(0.5, 0.5)
 +
self.text:setScale(self.params.textscalex, self.params.textscaley)
 +
self.text:setTextColor(self.params.textcolorup)
 +
textwidth, textheight = self.text:getWidth(), self.text:getHeight()
 
end
 
end
if self.text ~= nil then
+
-- first add pixel
self.text:setText(xtext)
+
if self.params.pixelcolorup then
else
+
if self.params.isautoscale and self.params.text then
self.text = TextField.new(self.font, xtext, xtext)
+
self.pixel = Pixel.new(
 +
self.params.pixelcolor, self.params.pixelalpha,
 +
textwidth + self.params.pixelpaddingx,
 +
textheight + self.params.pixelpaddingy)
 +
else
 +
self.pixel = Pixel.new(
 +
self.params.pixelcolor, self.params.pixelalpha,
 +
self.params.pixelpaddingx,
 +
self.params.pixelpaddingy)
 +
end
 +
self.pixel:setAnchorPoint(0.5, 0.5)
 +
self.pixel:setScale(self.params.pixelscalex, self.params.pixelscaley)
 +
self.sprite:addChild(self.pixel)
 
end
 
end
self.text:setAnchorPoint(0.5, 0.5)
+
-- then images
self.text:setScale(self.params.textscalex, self.params.textscaley)
+
if self.params.imgup then
self.text:setTextColor(self.params.textcolorup)
+
local texup = Texture.new(self.params.imgup)
self.textwidth = self.text:getWidth()
+
if self.params.isautoscale and self.params.text then
self.textheight = self.text:getHeight()
+
self.bmpup = Pixel.new(texup,
self.sprite:addChild(self.text)
+
textwidth + (self.params.imagepaddingx or self.params.defaultpadding),
-- has image
+
textheight + (self.params.imagepaddingy or self.params.defaultpadding))
if self.hasbmpup then
+
else
-- scale image
+
self.bmpup = Pixel.new(texup, self.params.imagepaddingx, self.params.imagepaddingy)
local sx, sy = 1, 1
 
if self.bmpupwidth < self.textwidth then
 
sx = self.params.imgscalex or (self.textwidth/self.bmpupwidth * 1.25)
 
sy = self.params.imgscaley or (self.textheight/self.bmpupheight * 2)
 
 
end
 
end
self.bmpup:setScale(sx, sy)
+
bmps[self.bmpup] = 1
 
end
 
end
if self.hasbmpdown then
+
if self.params.imgdown then
local sx, sy = 1, 1
+
local texdown = Texture.new(self.params.imgdown)
if self.bmpdownwidth < self.textwidth then
+
if self.params.isautoscale and self.params.text then
sx = self.params.imgscalex or (self.textwidth/self.bmpdownwidth * 1.25)
+
self.bmpdown = Pixel.new(texdown,
sy = self.params.imgscaley or (self.textheight/self.bmpdownheight * 2)
+
textwidth + (self.params.imagepaddingx or self.params.defaultpadding),
 +
textheight + (self.params.imagepaddingy or self.params.defaultpadding))
 +
else
 +
self.bmpdown = Pixel.new(texdown, self.params.imagepaddingx, self.params.imagepaddingy)
 
end
 
end
self.bmpdown:setScale(sx, sy)
+
bmps[self.bmpdown] = 2
 
end
 
end
if self.hasbmpdisabled then
+
if self.params.imgdisabled then
local sx, sy = 1, 1
+
local texdisabled = Texture.new(self.params.imgdisabled)
if self.bmpdisabledwidth < self.textwidth then
+
if self.params.isautoscale and self.params.text then
sx = self.params.imgscalex or (self.textwidth/self.bmpdisabledwidth * 1.25)
+
self.bmpdisabled = Pixel.new(texdisabled,
sy = self.params.imgscaley or (self.textheight/self.bmpdisabledheight * 2)
+
textwidth + (self.params.imagepaddingx or self.params.defaultpadding),
 +
textheight + (self.params.imagepaddingy or self.params.defaultpadding))
 +
else
 +
self.bmpdisabled = Pixel.new(texdisabled, self.params.imagepaddingx, self.params.imagepaddingy)
 
end
 
end
self.bmpdisabled:setScale(sx, sy)
+
bmps[self.bmpdisabled] = 3
 +
end
 +
-- image batch
 +
for k, _ in pairs(bmps) do
 +
k:setAnchorPoint(0.5, 0.5)
 +
k:setAlpha(self.params.imagealpha)
 +
local split = 9 -- magik number
 +
k:setNinePatch(math.floor(k:getWidth()/split), math.floor(k:getWidth()/split),
 +
math.floor(k:getHeight()/split), math.floor(k:getHeight()/split))
 +
self.sprite:addChild(k)
 
end
 
end
-- has pixel
+
-- finally add text on top of all
if self.haspixel then
+
if self.params.text then self.sprite:addChild(self.text) end
local sx, sy = 1, 1
+
-- and the tooltip text
if self.pixelwidth < self.textwidth then
+
if self.params.tooltiptext then
sx = self.textwidth/self.pixelwidth * 1.25
+
self.tooltiptext = TextField.new(nil, self.params.tooltiptext)
sy = self.textheight/self.pixelheight * 2
+
self.tooltiptext:setScale(self.params.tooltiptextscale)
end
+
self.tooltiptext:setTextColor(self.params.tooltiptextcolor)
self.pixel:setScale(sx, sy)
+
self.tooltiptext:setVisible(false)
 +
-- self.sprite:addChild(self.tooltiptext) -- best to add here?
 +
self:addChild(self.tooltiptext) -- or here to self?
 
end
 
end
end
+
-- fit the mouse catcher a little bigger than the button
 
+
self.catcher:setDimensions(self.sprite:getWidth() + 8 * 2.5, self.sprite:getHeight() + 8 * 2.5) -- magik
function ButtonTextUDDP:setTextColor(xcolor)
+
self.catcher:setAnchorPoint(0.5, 0.5)
self.text:setTextColor(xcolor or 0x0)
 
 
end
 
end
  
 
-- VISUAL STATE
 
-- VISUAL STATE
function ButtonTextUDDP:updateVisualState(xstate)
+
function ButtonTextP9UDDT:updateVisualState(xstate)
if self.disabled then -- button disabled state
+
if self.disabled then -- button is disabled
 
if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
 
if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
 
if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
 
if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
Line 966: Line 1,104:
 
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordisabled) end
 
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordisabled) end
 
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordisabled) end
 
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordisabled) end
 +
elseif not self.params.hover and self.params.tooltiptext then -- button does not hover but has a tooltip text
 +
if xstate and self.isclicked then -- button down state
 +
if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
 +
if self.params.imgdown ~= nil then self.bmpdown:setVisible(true) end
 +
if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
 +
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordown) end
 +
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordown) end
 +
else -- button up state
 +
if self.params.imgup ~= nil then self.bmpup:setVisible(true) end
 +
if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
 +
if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
 +
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolorup) end
 +
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
 +
end
 
else
 
else
 
if xstate then -- button down state
 
if xstate then -- button down state
Line 979: Line 1,131:
 
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolorup) end
 
if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolorup) end
 
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
 
if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
 +
end
 +
end
 +
 +
-- if self.params.tooltiptext and not self.disabled then -- you can choose this option: hides to tooltip when button is disabled
 +
if self.params.tooltiptext then -- or this option: shows the tooltip even when button is disabled
 +
if xstate then -- button hover state
 +
if self.disabled then
 +
self.tooltiptext:setText("( "..self.params.tooltiptext.." )")
 +
else
 +
self.tooltiptext:setText(self.params.tooltiptext)
 +
end
 +
self.tooltiptext:setVisible(true)
 +
else -- button no hover state
 +
self.tooltiptext:setText("")
 +
self.tooltiptext:setVisible(false)
 
end
 
end
 
end
 
end
 
end
 
end
  
function ButtonTextUDDP:setDisabled(xdisabled)
+
-- disabled
if self.disabled == xdisabled then
+
function ButtonTextP9UDDT:setDisabled(xdisabled)
return
+
if self.disabled == xdisabled then return end
end
 
 
self.disabled = xdisabled
 
self.disabled = xdisabled
 
self.focus = false
 
self.focus = false
Line 992: Line 1,158:
 
end
 
end
  
function ButtonTextUDDP:isDisabled()
+
function ButtonTextP9UDDT:isDisabled()
 
return self.disabled
 
return self.disabled
 
end
 
end
  
-- BUTTON LISTENERS
+
-- MOUSE LISTENERS
-- mouse
+
function ButtonTextP9UDDT:onMouseDown(e)
function ButtonTextUDDP:onMouseDown(e)
+
if self:hitTestPoint(e.x, e.y) and self:getParent():isVisible() then
if self:hitTestPoint(e.x, e.y) then
 
 
self.focus = true
 
self.focus = true
 +
self.isclicked = true -- 200608
 
self:updateVisualState(true)
 
self:updateVisualState(true)
 
e:stopPropagation()
 
e:stopPropagation()
 
end
 
end
 
end
 
end
function ButtonTextUDDP:onMouseMove(e)
+
function ButtonTextP9UDDT:onMouseMove(e)
if self:hitTestPoint(e.x, e.y) then
+
if self:hitTestPoint(e.x, e.y) and self:getParent():isVisible() then
 
self.focus = true
 
self.focus = true
self:updateVisualState(true)
+
-- self.isclicked = false -- 200608 to delete
e:stopPropagation()
+
-- e:stopPropagation() -- 20200820 to delete: prevents hover effect
end
+
else
if self.focus then
+
self.focus = false
if not self:hitTestPoint(e.x, e.y) then
+
-- e:stopPropagation() -- you may want to remove this line
self.focus = false
 
self:updateVisualState(false)
 
-- e:stopPropagation() -- you may want to comment this line
 
end
 
 
end
 
end
 +
self:updateVisualState(self.focus)
 
end
 
end
function ButtonTextUDDP:onMouseUp(e)
+
function ButtonTextP9UDDT:onMouseUp(e)
if self.focus then
+
if self.focus and self.isclicked then
 
self.focus = false
 
self.focus = false
self:updateVisualState(false)
+
self.isclicked = false -- 200608
 
if not self.disabled then
 
if not self.disabled then
self:dispatchEvent(Event.new("clicked")) -- button is clicked, dispatch "click" event
+
self:dispatchEvent(Event.new("clicked")) -- button is clicked
 
end
 
end
 
e:stopPropagation()
 
e:stopPropagation()
 
end
 
end
 
end
 
end
function ButtonTextUDDP:onMouseHover(e)
+
function ButtonTextP9UDDT:onMouseHover(e)
if self:hitTestPoint(e.x, e.y) then
+
if self.catcher:hitTestPoint(e.x, e.y) and self.catcher:isVisible() then
self.focus = true
 
self:updateVisualState(true)
 
else
 
 
self.focus = false
 
self.focus = false
self:updateVisualState(false)
 
 
end
 
end
end
+
if self.sprite:hitTestPoint(e.x, e.y) and self.sprite:isVisible() then
-- touch
+
if self.params.tooltiptext then self.tooltiptext:setPosition(self.sprite:globalToLocal(e.x, e.y)) end
function ButtonTextUDDP:onTouchesBegin(e)
+
self.focus = true
if self.focus then
 
e:stopPropagation()
 
end
 
end
 
function ButtonTextUDDP:onTouchesMove(e)
 
if self.focus then
 
e:stopPropagation()
 
end
 
end
 
function ButtonTextUDDP:onTouchesEnd(e)
 
if self.focus then
 
e:stopPropagation()
 
end
 
end
 
function ButtonTextUDDP:onTouchesCancel(e)
 
if self.focus then
 
self.focus = false
 
self:updateVisualState(false)
 
e:stopPropagation()
 
 
end
 
end
 +
self:updateVisualState(self.focus)
 
end
 
end
 
</source>
 
</source>
 
  
 
=== Toggle Button ===
 
=== Toggle Button ===

Revision as of 18:13, 25 August 2020

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

note: UDD = Up Down Disabled images.
note2: You may have to provide your own assets (fonts, gfx, …).

Simple Button

--[[
A generic button class

This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php
(C) 2010 - 2011 Gideros Mobile 
]]
--[[
-- USAGE
-- clickable button (arrow button)
local arrow = Texture.new("gfx/arrow_right.png")
local arrow_pressed = Texture.new("gfx/arrow_right_down.png")
local button = Button.new(Bitmap.new(arrow), Bitmap.new(arrow_pressed))
button:addEventListener("click", function()
	-- your code here
end)
]]

Button = Core.class(Sprite)

function Button:init(upState, downState) -- upstate and downstate are bitmaps
	self.upState = upState
	self.downState = downState
		
	self.focus = false

	-- set the visual state as "up"
	self:updateVisualState(false)

	-- register to all mouse and touch events
	self:addEventListener(Event.MOUSE_DOWN, self.onMouseDown, self)
	self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self)
	self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)

	self:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
	self:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
	self:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
	self:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
end

function Button:onMouseDown(event)
	if self:hitTestPoint(event.x, event.y) then
		self.focus = true
		self:updateVisualState(true)
		event:stopPropagation()
	end
end

function Button:onMouseMove(event)
	if self.focus then
		if not self:hitTestPoint(event.x, event.y) then	
			self.focus = false
			self:updateVisualState(false)
		end
		event:stopPropagation()
	end
end

function Button:onMouseUp(event)
	if self.focus then
		self.focus = false
		self:updateVisualState(false)
		self:dispatchEvent(Event.new("click"))	-- button is clicked, dispatch "click" event
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function Button:onTouchesBegin(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function Button:onTouchesMove(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function Button:onTouchesEnd(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if touches are cancelled, reset the state of the button
function Button:onTouchesCancel(event)
	if self.focus then
		self.focus = false;
		self:updateVisualState(false)
		event:stopPropagation()
	end
end

-- if state is true show downState else show upState
function Button:updateVisualState(state)
	if state then
		if self:contains(self.upState) then
			self:removeChild(self.upState)
		end
		
		if not self:contains(self.downState) then
			self:addChild(self.downState)
		end
	else
		if self:contains(self.downState) then
			self:removeChild(self.downState)
		end
		
		if not self:contains(self.upState) then
			self:addChild(self.upState)
		end
	end
end


Simple Text Button

--[[
ButtonTextBasic
A simple Button class with a Pixel and/or text. Ideal for in game action.
This code is CC0
github: mokalux
v 0.1.1: 2020-06-08 remove useless variables
v 0.1.0: 2020-04-02 init (based on the initial gideros generic button class)
]]
--[[
-- SAMPLES
	local mybtnquit = ButtonTextBasic.new({
		pixelcolorup=mypixelcolorup,
		text="X", font=g_font1, fontsize=32, textcolorup=mytextcolorup, textcolordown=mytextcolordown,
	})
	mybtnquit:setPosition(myappright - mybtnquit:getWidth() / 2, myapptop + mybtnquit:getHeight() / 2)
	self:addChild(mybtnquit)
	mybtnquit:addEventListener("clicked", function() self:goMenu() end)
]]
ButtonTextBasic = Core.class(Sprite)

function ButtonTextBasic:init(xparams)
	-- the params
	self.params = xparams or {}
	-- pixel?
	self.params.pixelcolorup = xparams.pixelcolorup or nil -- color
	self.params.pixelcolordown = xparams.pixelcolordown or self.params.pixelcolorup -- color
	self.params.pixelalpha = xparams.pixelalpha or 1 -- number
	self.params.pixelscalex = xparams.pixelscalex or 1 -- number
	self.params.pixelscaley = xparams.pixelscaley or 1 -- number
	self.params.pixelpaddingx = xparams.pixelpaddingx or 12 -- number
	self.params.pixelpaddingy = xparams.pixelpaddingy or 12 -- number
	-- text?
	self.params.text = xparams.text or nil -- string
	self.params.font = xparams.font or nil -- ttf font path
	self.params.fontsize = xparams.fontsize or 16 -- number
	self.params.textcolorup = xparams.textcolorup or 0x0 -- color
	self.params.textcolordown = xparams.textcolordown or self.params.textcolorup -- color
	self.params.textscalex = xparams.textscalex or 1 -- number
	self.params.textscaley = xparams.textscaley or self.params.textscalex -- number
	-- EXTRAS
	self.params.isautoscale = xparams.isautoscale or 1 -- number (default 1 = true)
	self.params.defaultpadding = xparams.defaultpadding or 12 -- number
	-- LET'S GO!
	if self.params.isautoscale == 0 then self.params.isautoscale = false else self.params.isautoscale = true end
	-- warnings
	if not self.params.pixelcolorup and not self.params.text then
		print("*** WARNING: YOUR BUTTON IS EMPTY! ***")
	else
		-- mouse catcher
		self.catcher = Pixel.new(0x0, 0, 1, 1)
		self:addChild(self.catcher)
		-- sprite holder
		self.sprite = Sprite.new()
		self:addChild(self.sprite)
		self:setButton()
	end
	-- update visual state
	self.focus = false
	self:updateVisualState(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

-- FUNCTIONS
function ButtonTextBasic:setButton()
	-- text
	local textwidth, textheight
	if self.params.text then
		local font
		if self.params.font ~= nil then
	--		font = TTFont.new(self.params.font, self.params.fontsize, "", true, 1) -- filtering, outline (number)
			font = TTFont.new(self.params.font, self.params.fontsize, "")
		end
		if self.text ~= nil then
			self.text:setButton(self.params.text)
		else
			self.text = TextField.new(font, self.params.text, self.params.text)
		end
		self.text:setAnchorPoint(0.5, 0.5)
		self.text:setScale(self.params.textscalex, self.params.textscaley)
		self.text:setTextColor(self.params.textcolorup)
		textwidth, textheight = self.text:getWidth(), self.text:getHeight()
	end
	-- first add pixel
	if self.params.pixelcolorup then
		if self.params.isautoscale and self.params.text then
			self.pixel = Pixel.new(
				self.params.pixelcolor, self.params.pixelalpha,
				textwidth + self.params.pixelpaddingx,
				textheight + self.params.pixelpaddingy)
		else
			self.pixel = Pixel.new(
				self.params.pixelcolor, self.params.pixelalpha,
				self.params.pixelpaddingx,
				self.params.pixelpaddingy)
		end
		self.pixel:setAnchorPoint(0.5, 0.5)
		self.pixel:setScale(self.params.pixelscalex, self.params.pixelscaley)
		self.sprite:addChild(self.pixel)
	end
	-- finally add text on top of all
	if self.params.text then self.sprite:addChild(self.text) end
	-- mouse catcher
	self.catcher:setDimensions(self.sprite:getWidth() + 8 * 2.5, self.sprite:getHeight() + 8 * 2.5) -- magik
	self.catcher:setAnchorPoint(0.5, 0.5)
end

-- VISUAL STATE
function ButtonTextBasic:updateVisualState(xstate)
	if xstate then -- button down state
		if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordown) end
		if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordown) end
	else -- button up state
		if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolorup) end
		if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
	end
end

-- MOUSE LISTENERS
function ButtonTextBasic:onMouseDown(e)
	if self:hitTestPoint(e.x, e.y) then
		self.focus = true
		self:updateVisualState(true)
		e:stopPropagation()
	end
end
function ButtonTextBasic:onMouseMove(e)
	if self:hitTestPoint(e.x, e.y) then
		self.focus = true
		e:stopPropagation()
	else
		self.focus = false
--		e:stopPropagation() -- you may want to delete this line
	end
	self:updateVisualState(self.focus)
end
function ButtonTextBasic:onMouseUp(e)
	if self.focus then
		self.focus = false
		self:dispatchEvent(Event.new("clicked")) -- button is clicked, dispatch "clicked" event
		e:stopPropagation()
	end
end

Button with an Up, Down and Disabled state (UDD)

--[[
A generic button class with an up, down and disabled state (UDD)

This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php
(C) 2010 - 2011 Gideros Mobile
]]
--[[
--usage
local button = ButtonUDD.new(
	Bitmap.new(Texture.new("gfx/button-up.png")), -- up state
	Bitmap.new(Texture.new("gfx/button-down.png")), -- down state
	Bitmap.new(Texture.new("gfx/button-disabled.png")) -- disabled state
)
button:setPosition(70, 130)
stage:addChild(button)
local function onRecord()
--	play:setDisabled(true)
--	record:removeFromParent()
--	stage:addChild(recordStop)
--	microphone:start()
end
button:addEventListener(Event.CLICK, onRecord)
]]

Event.CLICK = "click"

ButtonUDD = Core.class(Sprite)

function ButtonUDD:init(upState, downState, disabledState)
	self.upState = upState
	self.downState = downState
	self.disabledState = disabledState or upState

	self.focus = false
	self.disabled = false

	-- set the visual state as "up"
	self:updateVisualState(false)

	-- register to all mouse and touch events
	self:addEventListener(Event.MOUSE_DOWN, self.onMouseDown, self)
	self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self)
	self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)

	self:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
	self:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
	self:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
	self:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
end

function ButtonUDD:onMouseDown(event)
	if self:hitTestPoint(event.x, event.y) then
		self.focus = true
		self:updateVisualState(true)
		event:stopPropagation()
	end
end

function ButtonUDD:onMouseMove(event)
	if self.focus then
		if not self:hitTestPoint(event.x, event.y) then
			self.focus = false
			self:updateVisualState(false)
		end
		event:stopPropagation()
	end
end

function ButtonUDD:onMouseUp(event)
	if self.focus then
		self.focus = false
		self:updateVisualState(false)
		if not self.disabled then
			self:dispatchEvent(Event.new(Event.CLICK))	-- button is clicked, dispatch "click" event
		end
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function ButtonUDD:onTouchesBegin(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function ButtonUDD:onTouchesMove(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function ButtonUDD:onTouchesEnd(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if touches are cancelled, reset the state of the button
function ButtonUDD:onTouchesCancel(event)
	if self.focus then
		self.focus = false
		self:updateVisualState(false)
	end
end

-- if state is true show downState else show upState
function ButtonUDD:updateVisualState(state)
	self.upState:removeFromParent()
	self.downState:removeFromParent()
	self.disabledState:removeFromParent()

	if self.disabled then
		self:addChild(self.disabledState)
	else
		if state then
			self:addChild(self.downState)
		else
			self:addChild(self.upState)
		end
	end
end

function ButtonUDD:setDisabled(disabled)
	if self.disabled == disabled then
		return
	end

	self.disabled = disabled
	self.focus = false
	self:updateVisualState(false)
end

function ButtonUDD:isDisabled()
	return self.disabled
end


Button with Text and/or Images

note: You don't have to use an image, for example you can create a button with text only.

--[[
A Button class with text and/or image
This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php
github: mokalux
v 0.1.1: 2020-03-07 added optional mouse hover effect params (mouse hover effect default is true)
v 0.1.0: 2020-03-02 init (based on the initial gideros generic button class)
]]
--[[
-- sample usage
	local button = ButtonText.new(
		{
			text="01", textscalex=4, textcolorup=0x0, textcolordown=0xffff00,
			imgdown="gfx/ui/Blue.png", nohover=true,
		}
	)
	button:setPosition(128, 128)
	self:addChild(button)
	button:addEventListener("click", function() 
		-- your code here
	end)
]]
ButtonText = Core.class(Sprite)

function ButtonText:init(xparams)
	-- the params
	self.params = xparams or {}
	self.params.imgup = xparams.imgup or nil -- img up path
	self.params.imgdown = xparams.imgdown or self.params.imgup -- img down path
	self.params.imgscalex = xparams.imgscalex or nil -- number or nil = autoscale
	self.params.imgscaley = xparams.imgscaley or nil -- number or nil = autoscale
	self.params.text = xparams.text or nil -- string
	self.params.font = xparams.font or nil -- ttf font path
	self.params.fontsize = xparams.fontsize or 16 -- number
	self.params.textcolorup = xparams.textcolorup or 0x0 -- color
	self.params.textcolordown = xparams.textcolordown or self.params.textcolorup -- color
	self.params.textscalex = xparams.textscalex or 1 -- number
	self.params.textscaley = xparams.textscaley or self.params.textscalex -- number
	self.params.nohover = xparams.nohover or nil -- boolean
	-- let's go
	self.sprite = Sprite.new()
	self.sprite:setAnchorPoint(0.5,0.5)
	self:addChild(self.sprite)
	-- button has up state image?
	if self.params.imgup ~= nil then
		self.bmpup = Bitmap.new(Texture.new(self.params.imgup))
		self.bmpup:setAnchorPoint(0.5, 0.5)
		self.bmpupwidth = self.bmpup:getWidth()
		self.bmpupheight = self.bmpup:getHeight()
		self.sprite:addChild(self.bmpup)
		self.hasbmpup = true
	else
		self.hasbmpup = false
	end
	-- button has down state image?
	if self.params.imgdown ~= nil then
		self.bmpdown = Bitmap.new(Texture.new(self.params.imgdown))
		self.bmpdown:setAnchorPoint(0.5, 0.5)
		self.bmpdownwidth = self.bmpdown:getWidth()
		self.bmpdownheight = self.bmpdown:getHeight()
		self.sprite:addChild(self.bmpdown)
		self.hasbmpdown = true
	else
		self.hasbmpdown = false
	end
	-- button has text?
	if self.params.text ~= nil then
		self:setText(self.params.text)
		self.hastext = true
	else
		self.hastext = false
	end
	-- warnings
	if not self.hasbmpup and not self.hasbmpdown and not self.hastext then
		print("*** WARNING: BUTTONTEXT NEEDS AT LEAST SOME TEXT OR SOME BITMAPS! ***")
	end
	-- update visual state
	self.focus = false
	self:updateVisualState(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)
	self:addEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
	if self.params.nohover then
--		print("*** no mouse hover effect ***")
		self:removeEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
	end
	-- mobile
	self:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
	self:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
	self:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
	self:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
end

-- FUNCTIONS
function ButtonText:setText(xtext)
	if self.params.font ~= nil then
		self.font = TTFont.new(self.params.font, self.params.fontsize)
	end
	if self.text ~= nil then
		self.text:setText(xtext)
	else
		self.text = TextField.new(self.font, xtext, xtext)
	end
	self.text:setAnchorPoint(0.5, 0.5)
	self.text:setScale(self.params.textscalex, self.params.textscaley)
	self.text:setTextColor(self.params.textcolorup)
	self.textwidth = self.text:getWidth()
	self.textheight = self.text:getHeight()
	self.sprite:addChild(self.text)
	-- scale image
	if self.hasbmpup then
		local sx, sy = 1, 1
		if self.bmpupwidth < self.textwidth then
			sx = self.params.imgscalex or (self.textwidth/self.bmpupwidth * 1.25)
			sy = self.params.imgscaley or (self.textheight/self.bmpupheight * 2)
		end
		self.bmpup:setScale(sx, sy)
	end
	if self.hasbmpdown then
		local sx, sy = 1, 1
		if self.bmpdownwidth < self.textwidth then
			sx = self.params.imgscalex or (self.textwidth/self.bmpdownwidth * 1.25)
			sy = self.params.imgscaley or (self.textheight/self.bmpdownheight * 2)
		end
		self.bmpdown:setScale(sx, sy)
	end
end

function ButtonText:setTextColor(xcolor)
	self.text:setTextColor(xcolor or 0x0)
end

-- VISUAL STATE
function ButtonText:updateVisualState(xisdown)
	if xisdown then
		if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
		if self.params.imgdown ~= nil then self.bmpdown:setVisible(true) end
		if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordown) end
	else
		if self.params.imgup ~= nil then self.bmpup:setVisible(true) end
		if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
		if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
	end
end

-- BUTTON LISTENERS
-- mouse
function ButtonText:onMouseDown(event)
	if self:hitTestPoint(event.x, event.y) then
		self.focus = true
		self:updateVisualState(true)
		event:stopPropagation()
	end
end
function ButtonText:onMouseMove(event)
	if self:hitTestPoint(event.x, event.y) then
		self.focus = true
		self:updateVisualState(true)
		event:stopPropagation()
	end
	if not self:hitTestPoint(event.x, event.y) then
		self.focus = false
		self:updateVisualState(false)
--		event:stopPropagation() -- you may want to comment this line
	end
end
function ButtonText:onMouseUp(event)
	if self.focus then
		self.focus = false
		self:updateVisualState(false)
		self:dispatchEvent(Event.new("click"))
		event:stopPropagation()
	end
end
function ButtonText:onMouseHover(event)
	if self:hitTestPoint(event.x, event.y) then
		self.focus = true
		self:updateVisualState(true)
	else
		self.focus = false
		self:updateVisualState(false)
	end
end
-- mobile
function ButtonText:onTouchesBegin(event)
	if self.focus then
		event:stopPropagation()
	end
end
function ButtonText:onTouchesMove(event)
	if self.focus then
		event:stopPropagation()
	end
end
function ButtonText:onTouchesEnd(event)
	if self.focus then
		event:stopPropagation()
	end
end
function ButtonText:onTouchesCancel(event)
	if self.focus then
		self.focus = false
		self:updateVisualState(false)
		event:stopPropagation()
	end
end


Button with Text and/or Images UDD

This button has it all (almost) :-)
note: You don't have to use all parameters (UDD), for example you can create a button with text only.

--[[
A Button class with text and/or image with Up state, Down state, Disabled state (UDD)
This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php
github: mokalux
v 0.1.0: 2020-03-09 init (based on the initial gideros generic button class)
]]
--[[
-- sample usage
	local button = ButtonTextUDD.new(
		{
			text="01", textscalex=4, textcolorup=0x0, textcolordown=0xffff00,
			imgdown="gfx/ui/Blue.png",
			nohover=false,
		}
	)
	button:setPosition(64, 2 * 16)
	stage:addChild(button)

	local button2 = ButtonTextUDD.new(
		{
			text="02 CAN DO", textscalex=4, textcolorup=0x0, textcolordown=0xffff00,
			imgup="gfx/ui/blue (2).png", imgdown="gfx/ui/Blue.png", imgdisabled="gfx/ui/blocker2.png",
			nohover=true,
		}
	)
	button2:setPosition(64, 4 * 16)
	stage:addChild(button2)

	button:addEventListener("clicked", function()
		button2:setDisabled(not button2:isDisabled())
	end)
	button2:addEventListener("click", function()
		-- your code here
	end)
]]
ButtonTextUDD = Core.class(Sprite)

function ButtonTextUDD:init(xparams)
	-- the params
	self.params = xparams or {}
	self.params.imgup = xparams.imgup or nil -- img up path
	self.params.imgdown = xparams.imgdown or self.params.imgup -- img down path
	self.params.imgdisabled = xparams.imgdisabled or self.params.imgup -- img disabled path
	self.params.imgscalex = xparams.imgscalex or nil -- number or nil = autoscale
	self.params.imgscaley = xparams.imgscaley or nil -- number or nil = autoscale
	self.params.text = xparams.text or nil -- string
	self.params.font = xparams.font or nil -- ttf font path
	self.params.fontsize = xparams.fontsize or 16 -- number
	self.params.textcolorup = xparams.textcolorup or 0x0 -- color
	self.params.textcolordown = xparams.textcolordown or self.params.textcolorup -- color
	self.params.textcolordisabled = xparams.textcolordisabled or 0x555555 -- color
	self.params.textscalex = xparams.textscalex or 1 -- number
	self.params.textscaley = xparams.textscaley or self.params.textscalex -- number
	self.params.nohover = xparams.nohover or nil -- boolean
	-- let's go
	self.sprite = Sprite.new()
	self.sprite:setAnchorPoint(0.5,0.5)
	self:addChild(self.sprite)
	-- button has up state image?
	if self.params.imgup ~= nil then
		self.bmpup = Bitmap.new(Texture.new(self.params.imgup))
		self.bmpup:setAnchorPoint(0.5, 0.5)
		self.bmpupwidth = self.bmpup:getWidth()
		self.bmpupheight = self.bmpup:getHeight()
		self.sprite:addChild(self.bmpup)
		self.hasbmpup = true
	else
		self.hasbmpup = false
	end
	-- button has down state image?
	if self.params.imgdown ~= nil then
		self.bmpdown = Bitmap.new(Texture.new(self.params.imgdown))
		self.bmpdown:setAnchorPoint(0.5, 0.5)
		self.bmpdownwidth = self.bmpdown:getWidth()
		self.bmpdownheight = self.bmpdown:getHeight()
		self.sprite:addChild(self.bmpdown)
		self.hasbmpdown = true
	else
		self.hasbmpdown = false
	end
	-- button has disabled state image?
	if self.params.imgdisabled ~= nil then
		self.bmpdisabled = Bitmap.new(Texture.new(self.params.imgdisabled))
		self.bmpdisabled:setAnchorPoint(0.5, 0.5)
		self.bmpdisabledwidth = self.bmpdown:getWidth()
		self.bmpdisabledheight = self.bmpdown:getHeight()
		self.sprite:addChild(self.bmpdisabled)
		self.hasbmpdisabled = true
	else
		self.hasbmpdisabled = false
	end
	-- button has text?
	if self.params.text ~= nil then
		self:setText(self.params.text)
		self.hastext = true
	else
		self.hastext = false
	end
	-- warnings
	if not self.hasbmpup and not self.hasbmpdown and not self.hasbmpdisabled and not self.hastext then
		print("*** WARNING: BUTTONTEXT NEEDS AT LEAST SOME TEXT OR SOME BITMAPS! ***")
	end
	-- update visual state
	self.focus = false
	self.disabled = false
	self:updateVisualState(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)
	self:addEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
	if self.params.nohover then
		print("*** no mouse hover effect ***")
		self:removeEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
	end
	-- mobile
	self:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
	self:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
	self:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
	self:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
end

-- FUNCTIONS
function ButtonTextUDD:setText(xtext)
	if self.params.font ~= nil then
		self.font = TTFont.new(self.params.font, self.params.fontsize)
	end
	if self.text ~= nil then
		self.text:setText(xtext)
	else
		self.text = TextField.new(self.font, xtext, xtext)
	end
	self.text:setAnchorPoint(0.5, 0.5)
	self.text:setScale(self.params.textscalex, self.params.textscaley)
	self.text:setTextColor(self.params.textcolorup)
	self.textwidth = self.text:getWidth()
	self.textheight = self.text:getHeight()
	self.sprite:addChild(self.text)
	-- scale image
	if self.hasbmpup then
		local sx, sy = 1, 1
		if self.bmpupwidth < self.textwidth then
			sx = self.params.imgscalex or (self.textwidth/self.bmpupwidth * 1.25)
			sy = self.params.imgscaley or (self.textheight/self.bmpupheight * 2)
		end
		self.bmpup:setScale(sx, sy)
	end
	if self.hasbmpdown then
		local sx, sy = 1, 1
		if self.bmpdownwidth < self.textwidth then
			sx = self.params.imgscalex or (self.textwidth/self.bmpdownwidth * 1.25)
			sy = self.params.imgscaley or (self.textheight/self.bmpdownheight * 2)
		end
		self.bmpdown:setScale(sx, sy)
	end
	if self.hasbmpdisabled then
		local sx, sy = 1, 1
		if self.bmpdisabledwidth < self.textwidth then
			sx = self.params.imgscalex or (self.textwidth/self.bmpdisabledwidth * 1.25)
			sy = self.params.imgscaley or (self.textheight/self.bmpdisabledheight * 2)
		end
		self.bmpdisabled:setScale(sx, sy)
	end
end

function ButtonTextUDD:setTextColor(xcolor)
	self.text:setTextColor(xcolor or 0x0)
end

-- VISUAL STATE
function ButtonTextUDD:updateVisualState(xstate)
	if self.disabled then -- button disabled state
		if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
		if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
		if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(true) end
		if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordisabled) end
	else
		if xstate then -- button down state
			if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
			if self.params.imgdown ~= nil then self.bmpdown:setVisible(true) end
			if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
			if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordown) end
		else -- button up state
			if self.params.imgup ~= nil then self.bmpup:setVisible(true) end
			if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
			if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
			if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
		end
	end
end

function ButtonTextUDD:setDisabled(xdisabled)
	if self.disabled == xdisabled then
		return
	end
	self.disabled = xdisabled
	self.focus = false
	self:updateVisualState(false)
end

function ButtonTextUDD:isDisabled()
	return self.disabled
end

-- BUTTON LISTENERS
-- mouse
function ButtonTextUDD:onMouseDown(e)
	if self:hitTestPoint(e.x, e.y) then
		self.focus = true
		self:updateVisualState(true)
		e:stopPropagation()
	end
end
function ButtonTextUDD:onMouseMove(e)
	if self:hitTestPoint(e.x, e.y) then
		self.focus = true
		self:updateVisualState(true)
		e:stopPropagation()
	end
	if self.focus then
		if not self:hitTestPoint(e.x, e.y) then
			self.focus = false
			self:updateVisualState(false)
--			e:stopPropagation() -- you may want to comment this line
		end
	end
end
function ButtonTextUDD:onMouseUp(e)
	if self.focus then
		self.focus = false
		self:updateVisualState(false)
		if not self.disabled then
			self:dispatchEvent(Event.new("clicked"))	-- button is clicked, dispatch "click" event
		end
		e:stopPropagation()
	end
end
function ButtonTextUDD:onMouseHover(e)
	if self:hitTestPoint(e.x, e.y) then
		self.focus = true
		self:updateVisualState(true)
	else
		self.focus = false
		self:updateVisualState(false)
	end
end
-- touch
function ButtonTextUDD:onTouchesBegin(e)
	if self.focus then
		e:stopPropagation()
	end
end
function ButtonTextUDD:onTouchesMove(e)
	if self.focus then
		e:stopPropagation()
	end
end
function ButtonTextUDD:onTouchesEnd(e)
	if self.focus then
		e:stopPropagation()
	end
end
function ButtonTextUDD:onTouchesCancel(e)
	if self.focus then
		self.focus = false
		self:updateVisualState(false)
		e:stopPropagation()
	end
end


Button with Text, Pixel, Images 9 Patch, UDD, Tooltip

This button is the most complete :-)
note: You don't have to use all parameters, for example you can create a button with text only.

--[[
ButtonTextP9UDDT
A Button class with text, Pixel, images 9patch (Up, Down, Disabled) and Tooltip
This code is CC0
github: mokalux
v 0.1.5: 2020-08-25 replaced font params with ttf params for better control
v 0.1.41: 2020-08-19 added tooltip text scale and color
v 0.1.4: 2020-06-08 removed useless variables + the class was somehow broken :/
v 0.1.3: 2020-03-30 added tooltiptext
v 0.1.2: 2020-03-29 added nine patch
v 0.1.1: 2020-03-28 added pixel
v 0.1.0: 2020-03-28 init (based on the initial gideros generic button class)
]]
--[[
-- SAMPLE
	-- BUTTON QUIT
	local mybtnquit = ButtonTextP9UDDT.new({
		pixelcolorup=0x0, pixelpaddingx=3, pixelpaddingy=3,
		text="QUIT", ttf=mycompositefont,
		textcolorup=0xffffff, textcolordown=0xff00ff,
		hover=true,
	})
	mybtnquit:setPosition(64, 64)
	stage:addChild(mybtnquit)
	mybtnquit:addEventListener("clicked", function() self:goExit() end)
	mybtnquit:setDisabled(true)
]]
ButtonTextP9UDDT = Core.class(Sprite)

function ButtonTextP9UDDT:init(xparams)
	-- the params table
	self.params = xparams or {}
	-- pixel?
	self.params.pixelcolorup = xparams.pixelcolorup or nil -- color
	self.params.pixelcolordown = xparams.pixelcolordown or self.params.pixelcolorup -- color
	self.params.pixelcolordisabled = xparams.pixelcolordisabled or 0x555555 -- color
	self.params.pixelalpha = xparams.pixelalpha or 1 -- number
	self.params.pixelscalex = xparams.pixelscalex or 1 -- number
	self.params.pixelscaley = xparams.pixelscaley or 1 -- number
	self.params.pixelpaddingx = xparams.pixelpaddingx or 12 -- number
	self.params.pixelpaddingy = xparams.pixelpaddingy or 12 -- number
	-- textures?
	self.params.imgup = xparams.imgup or nil -- img up path
	self.params.imgdown = xparams.imgdown or self.params.imgup -- img down path
	self.params.imgdisabled = xparams.imgdisabled or self.params.imgup -- img disabled path
	self.params.imagealpha = xparams.imagealpha or 1 -- number
	self.params.imgscalex = xparams.imgscalex or 1 -- number
	self.params.imgscaley = xparams.imgscaley or 1 -- number
	self.params.imagepaddingx = xparams.imagepaddingx or nil -- number (nil = auto, the image width)
	self.params.imagepaddingy = xparams.imagepaddingy or nil -- number (nil = auto, the image height)
	-- text?
	self.params.text = xparams.text or nil -- string
	self.params.ttf = xparams.ttf or nil -- ttf
	self.params.textcolorup = xparams.textcolorup or 0x0 -- color
	self.params.textcolordown = xparams.textcolordown or self.params.textcolorup -- color
	self.params.textcolordisabled = xparams.textcolordisabled or 0x777777 -- color
	self.params.textscalex = xparams.textscalex or 1 -- number
	self.params.textscaley = xparams.textscaley or self.params.textscalex -- number
	-- EXTRAS
	self.params.isautoscale = xparams.isautoscale or 1 -- number (default 1 = true)
	self.params.hover = xparams.hover or 0 -- number (default 0 = false)
	self.params.defaultpadding = xparams.defaultpadding or 12 -- number
	self.params.tooltiptext = xparams.tooltiptext or nil -- string
	self.params.tooltiptextscale = xparams.tooltiptextscale or 2
	self.params.tooltiptextcolor = xparams.tooltiptextcolor or 0x0
	-- LET'S GO!
	if self.params.isautoscale == 0 then self.params.isautoscale = false else self.params.isautoscale = true end
	if self.params.hover == 0 then self.params.hover = false else self.params.hover = true end
	-- warnings
	if not self.params.imgup and not self.params.imgdown and not self.params.imgdisabled
		and not self.params.pixelcolorup and not self.params.text and not self.params.tooltiptext then
		print("*** WARNING: YOUR BUTTON IS EMPTY! ***")
	else
		-- draws a pixel around the button to catch the mouse leaving the button
		self.catcher = Pixel.new(0x0, 0.25, 1, 1)
		self:addChild(self.catcher)
		-- button sprite holder
		self.sprite = Sprite.new()
		self:addChild(self.sprite)
		self:setButton()
	end
	-- update visual state
	self.focus = false
	self.disabled = false
	self:updateVisualState(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)
	self:addEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
	if not self.params.hover and not self.params.tooltiptext then
--		print("*** no mouse hover effect ***")
		self:removeEventListener(Event.MOUSE_HOVER, self.onMouseHover, self)
	end
end

-- FUNCTIONS
function ButtonTextP9UDDT:setButton()
	local textwidth, textheight
	local bmps = {}
	-- text
	if self.params.text then
		self.text = TextField.new(self.params.ttf, self.params.text, self.params.text)
		self.text:setAnchorPoint(0.5, 0.5)
		self.text:setScale(self.params.textscalex, self.params.textscaley)
		self.text:setTextColor(self.params.textcolorup)
		textwidth, textheight = self.text:getWidth(), self.text:getHeight()
	end
	-- first add pixel
	if self.params.pixelcolorup then
		if self.params.isautoscale and self.params.text then
			self.pixel = Pixel.new(
				self.params.pixelcolor, self.params.pixelalpha,
				textwidth + self.params.pixelpaddingx,
				textheight + self.params.pixelpaddingy)
		else
			self.pixel = Pixel.new(
				self.params.pixelcolor, self.params.pixelalpha,
				self.params.pixelpaddingx,
				self.params.pixelpaddingy)
		end
		self.pixel:setAnchorPoint(0.5, 0.5)
		self.pixel:setScale(self.params.pixelscalex, self.params.pixelscaley)
		self.sprite:addChild(self.pixel)
	end
	-- then images
	if self.params.imgup then
		local texup = Texture.new(self.params.imgup)
		if self.params.isautoscale and self.params.text then
			self.bmpup = Pixel.new(texup,
				textwidth + (self.params.imagepaddingx or self.params.defaultpadding),
				textheight + (self.params.imagepaddingy or self.params.defaultpadding))
		else
			self.bmpup = Pixel.new(texup, self.params.imagepaddingx, self.params.imagepaddingy)
		end
		bmps[self.bmpup] = 1
	end
	if self.params.imgdown then
		local texdown = Texture.new(self.params.imgdown)
		if self.params.isautoscale and self.params.text then
			self.bmpdown = Pixel.new(texdown,
				textwidth + (self.params.imagepaddingx or self.params.defaultpadding),
				textheight + (self.params.imagepaddingy or self.params.defaultpadding))
		else
			self.bmpdown = Pixel.new(texdown, self.params.imagepaddingx, self.params.imagepaddingy)
		end
		bmps[self.bmpdown] = 2
	end
	if self.params.imgdisabled then
		local texdisabled = Texture.new(self.params.imgdisabled)
		if self.params.isautoscale and self.params.text then
			self.bmpdisabled = Pixel.new(texdisabled,
				textwidth + (self.params.imagepaddingx or self.params.defaultpadding),
				textheight + (self.params.imagepaddingy or self.params.defaultpadding))
		else
			self.bmpdisabled = Pixel.new(texdisabled, self.params.imagepaddingx, self.params.imagepaddingy)
		end
		bmps[self.bmpdisabled] = 3
	end
	-- image batch
	for k, _ in pairs(bmps) do
		k:setAnchorPoint(0.5, 0.5)
		k:setAlpha(self.params.imagealpha)
		local split = 9 -- magik number
		k:setNinePatch(math.floor(k:getWidth()/split), math.floor(k:getWidth()/split),
			math.floor(k:getHeight()/split), math.floor(k:getHeight()/split))
		self.sprite:addChild(k)
	end
	-- finally add text on top of all
	if self.params.text then self.sprite:addChild(self.text) end
	-- and the tooltip text
	if self.params.tooltiptext then
		self.tooltiptext = TextField.new(nil, self.params.tooltiptext)
		self.tooltiptext:setScale(self.params.tooltiptextscale)
		self.tooltiptext:setTextColor(self.params.tooltiptextcolor)
		self.tooltiptext:setVisible(false)
--		self.sprite:addChild(self.tooltiptext) -- best to add here?
		self:addChild(self.tooltiptext) -- or here to self?
	end
	-- fit the mouse catcher a little bigger than the button
	self.catcher:setDimensions(self.sprite:getWidth() + 8 * 2.5, self.sprite:getHeight() + 8 * 2.5) -- magik
	self.catcher:setAnchorPoint(0.5, 0.5)
end

-- VISUAL STATE
function ButtonTextP9UDDT:updateVisualState(xstate)
	if self.disabled then -- button is disabled
		if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
		if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
		if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(true) end
		if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordisabled) end
		if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordisabled) end
	elseif not self.params.hover and self.params.tooltiptext then -- button does not hover but has a tooltip text
		if xstate and self.isclicked then -- button down state
			if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
			if self.params.imgdown ~= nil then self.bmpdown:setVisible(true) end
			if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
			if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordown) end
			if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordown) end
		else -- button up state
			if self.params.imgup ~= nil then self.bmpup:setVisible(true) end
			if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
			if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
			if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolorup) end
			if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
		end
	else
		if xstate then -- button down state
			if self.params.imgup ~= nil then self.bmpup:setVisible(false) end
			if self.params.imgdown ~= nil then self.bmpdown:setVisible(true) end
			if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
			if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolordown) end
			if self.params.text ~= nil then self.text:setTextColor(self.params.textcolordown) end
		else -- button up state
			if self.params.imgup ~= nil then self.bmpup:setVisible(true) end
			if self.params.imgdown ~= nil then self.bmpdown:setVisible(false) end
			if self.params.imgdisabled ~= nil then self.bmpdisabled:setVisible(false) end
			if self.params.pixelcolorup ~= nil then self.pixel:setColor(self.params.pixelcolorup) end
			if self.params.text ~= nil then self.text:setTextColor(self.params.textcolorup) end
		end
	end

--	if self.params.tooltiptext and not self.disabled then -- you can choose this option: hides to tooltip when button is disabled
	if self.params.tooltiptext then -- or this option: shows the tooltip even when button is disabled
		if xstate then -- button hover state
			if self.disabled then
				self.tooltiptext:setText("( "..self.params.tooltiptext.." )")
			else
				self.tooltiptext:setText(self.params.tooltiptext)
			end
			self.tooltiptext:setVisible(true)
		else -- button no hover state
			self.tooltiptext:setText("")
			self.tooltiptext:setVisible(false)
		end
	end
end

-- disabled
function ButtonTextP9UDDT:setDisabled(xdisabled)
	if self.disabled == xdisabled then return end
	self.disabled = xdisabled
	self.focus = false
	self:updateVisualState(false)
end

function ButtonTextP9UDDT:isDisabled()
	return self.disabled
end

-- MOUSE LISTENERS
function ButtonTextP9UDDT:onMouseDown(e)
	if self:hitTestPoint(e.x, e.y) and self:getParent():isVisible() then
		self.focus = true
		self.isclicked = true -- 200608
		self:updateVisualState(true)
		e:stopPropagation()
	end
end
function ButtonTextP9UDDT:onMouseMove(e)
	if self:hitTestPoint(e.x, e.y) and self:getParent():isVisible() then
		self.focus = true
--		self.isclicked = false -- 200608 to delete
--		e:stopPropagation() -- 20200820 to delete: prevents hover effect
	else
		self.focus = false
--		e:stopPropagation() -- you may want to remove this line
	end
	self:updateVisualState(self.focus)
end
function ButtonTextP9UDDT:onMouseUp(e)
	if self.focus and self.isclicked then
		self.focus = false
		self.isclicked = false -- 200608
		if not self.disabled then
			self:dispatchEvent(Event.new("clicked")) -- button is clicked
		end
		e:stopPropagation()
	end
end
function ButtonTextP9UDDT:onMouseHover(e)
	if self.catcher:hitTestPoint(e.x, e.y) and self.catcher:isVisible() then
		self.focus = false
	end
	if self.sprite:hitTestPoint(e.x, e.y) and self.sprite:isVisible() then
		if self.params.tooltiptext then self.tooltiptext:setPosition(self.sprite:globalToLocal(e.x, e.y)) end
		self.focus = true
	end
	self:updateVisualState(self.focus)
end

Toggle Button

--[[
ToggleButton v1.0
 
v1.0 - 19.3.2013
Initial release
 
Free to modify and use!
Matjaž Bravc
]]
--[[
-- USAGE
local btntoggle = ToggleButton.new(Bitmap.new(Texture.new("gfx/off.png", true)), Bitmap.new(Texture.new("gfx/on.png", true)))
stage:addChild(btntoggle)
btntoggle:addEventListener("click", function()
	print(btntoggle:isPressed())
end)
]]

ToggleButton = Core.class(Sprite)

function ToggleButton:init(upState, downState)
	self.upState = upState
	self.downState = downState

	self.pressed = false
	self.focus = false

	self:updateVisualState(self.pressed)

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

	self:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
	self:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
	self:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
	self:addEventListener(Event.TOUCHES_CANCEL, self.onTouchesCancel, self)
end

function ToggleButton:onMouseDown(event)
	if self:hitTestPoint(event.x, event.y) then
		self.focus = true
		event:stopPropagation()
	end
end

function ToggleButton:onMouseMove(event)
	if self.focus then
		if not self:hitTestPoint(event.x, event.y) then
			self.focus = false
		end
		event:stopPropagation()
	end
end

function ToggleButton:onMouseUp(event)
	if self.focus then
		self.focus = false
		self:updateVisualState(not self.pressed)
		self:dispatchEvent(Event.new("click"))
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function ToggleButton:onTouchesBegin(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function ToggleButton:onTouchesMove(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if button is on focus, stop propagation of touch events
function ToggleButton:onTouchesEnd(event)
	if self.focus then
		event:stopPropagation()
	end
end

-- if touches are cancelled, reset the state of the button
function ToggleButton:onTouchesCancel(event)
	if self.focus then
		self.focus = false
		self:updateVisualState(false) -- XXX
		event:stopPropagation()
	end
end

-- if state is true show downState else show upState
function ToggleButton:updateVisualState(state)
	self.pressed = state

	-- Modification to allow single state buttons (checkboxes etc)
	if not self.downState then
		if not self:contains(self.upState) then
			self:addChild(self.upState)
		end
		return
	end

	if self.pressed then
		if self:contains(self.upState) then
			self:removeChild(self.upState)
		end
		if not self:contains(self.downState) then
			self:addChild(self.downState)
		end
	else
		if self:contains(self.downState) then
			self:removeChild(self.downState)
		end
		if not self:contains(self.upState) then
			self:addChild(self.upState)
		end
	end
end

function ToggleButton:setPressed(xbool)
	self:updateVisualState(xbool)
end

function ToggleButton:isPressed()
	return self.pressed
end

Template:Welcome!