UI Buttons

From GiderosMobile
Revision as of 16:35, 10 March 2020 by MoKaLux (talk | contribs) (added one more button :-))

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, …).

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


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

--[[
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()
	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 :-)

--[[
A Button class with text and/or image width 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()
		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


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:isPressed()
	return self.pressed
end

Template:Welcome!