Skip to content

Instantly share code, notes, and snippets.

@JMV38
Created January 24, 2014 21:12
Show Gist options
  • Select an option

  • Save JMV38/8606537 to your computer and use it in GitHub Desktop.

Select an option

Save JMV38/8606537 to your computer and use it in GitHub Desktop.
Codea Project Gist Created with AutoGist
AutoGist Tab Order Version: 2.2.8
------------------------------
This file should not be included in the Codea project.
#Buttons
#Main
Buttons = {}
-- this class manages all buttons
-- ########### INSTRUCTIONS ####################
Buttons.tab = "Buttons" -- this must be the name of this tab
--[[
-- this is how to install the buttons in your main tab:
function setup()
Buttons:editMode(true)
end
function draw()
-- your draw here
Buttons:draw()
end
function touched(t)
if Buttons:touched(t) then return end
-- your touch here
end
--]]
-- ########### END OF INSTRUCTIONS ##############
Buttons.edit = false -- true qctivate edit mode
Buttons.list = {}
Buttons.buttonsCreated = false
function Buttons:editMode(edit)
if not Buttons.buttonsCreated then
if edit then displayMode(STANDARD) end
if self.createButtons then self:createButtons() end
Buttons.buttonsCreated = true
end
self.edit = edit
if self.edit then -- show the menu
self:parameterTopMenu()
end
for i,b in ipairs(Buttons.list) do b.edit = edit end
end
function Buttons:draw()
pushMatrix()pushStyle()
resetMatrix()resetStyle()
for i,b in ipairs(Buttons.list) do b:draw() end
popMatrix()popStyle()
end
function Buttons:touched(touch)
local n = #Buttons.list
for i=1,n do
local b = Buttons.list[n-i+1]
if b:touched(touch) then return true end
end
return false
end
function Buttons:register(b)
local n = #self.list+1
self.list[n] = b
self.list[b.name] = b
end
function Buttons:delete(but)
for i,b in ipairs(Buttons.list) do
if b==but then
table.remove(Buttons.list,i)
end
end
Buttons.list[but.name] = nil
Buttons.parameterTopMenu()
end
function Buttons.new()
local n = 0
local name
repeat
n = n + 1
name = "button"..tostring(n)
until Buttons.list[name] == nil
local txt = "text "..tostring(n)
local b = Button({name=name, txt = txt})
Buttons:register(b)
end
function Buttons.save()
local d = {}
d[#d+1] = "function Buttons:createButtons()"
for i,b in ipairs(Buttons.list) do
d[#d+1] = "Buttons:register("
d[#d+1] = b:tostring()
d[#d+1] = ")"
end
d[#d+1] = "end"
local strOut = table.concat(d,"\n")
local str = readProjectTab(Buttons.tab)
local splitter,start,plainText = "-- list of buttons\n",1,true
local a,b = str:find(splitter,start,plainText)
local s = str:sub(1, b)
s = s .. strOut
saveProjectTab(Buttons.tab,s)
output.clear()
print("saved")
end
function Buttons.switchMode()
Buttons:editMode( not Buttons.edit )
output.clear()
print("edit mode : "..tostring(Buttons.edit))
if Buttons.edit then
print("you can edit your buttons, but callbacks do not work")
else
print("callbacks work, but buttons cant be edited")
end
Buttons.parameterTopMenu()
end
function Buttons.setAutosave(choice)
Buttons.autosave = choice
end
function Buttons.parameterTopMenu()
parameter.clear()
parameter.action("BACK")
if Buttons.edit then
parameter.action("save changes",Buttons.save)
parameter.boolean("B_autosave",Buttons.autosave,Buttons.setAutosave)
parameter.action("new button",Buttons.new)
parameter.action("tap a button to edit")
end
parameter.action("edit mode true/false",Buttons.switchMode)
Buttons.current = nil -- no button selected
end
function Buttons.saveLast(key,value)
Buttons.lastKey = key
Buttons.lastValue = value
end
function Buttons.applyLastToAll()
local key = Buttons.lastKey
local value = Buttons.lastValue
for i,b in ipairs(Buttons.list) do b[key] = value ; b:reset(b) end
end
function Buttons.applyCurrentButtonToAll()
local except = {name=true,txt=true,callback=true,x=true,y=true,rx=true,ry=true}
for i,b in ipairs(Buttons.list) do
for key,value in pairs(Buttons.current) do
if not except[key] then
b[key] = value
end
end
b:reset(b)
end
if Buttons.autosave then Buttons:save() end
end
-- ###############################################################
Button = class()
-- returns true if touched, fire callback if any
function Button:init(d)
self.name = d.name
self:reset(d)
tween.delay(1,self.reset,self,self)
end
function Button:reset(d)
local d = d or {}
local default = self.default
for key,value in pairs(default) do
if d[key]~= nil then self[key] = d[key] else self[key] = value end
end
pushMatrix() pushStyle() resetMatrix() resetStyle()
-- position
if self.rx >= 0 then self.x = self.rx else self.x = WIDTH + self.rx end
if self.ry >= 0 then self.y = self.ry else self.y = HEIGHT + self.ry end
-- state
self:setOff()
-- size
font( self.fontName)
fontSize(self.fontSize)
local w,h = textSize(self.txt)
local wo,ho,ro = self.w,self.h,self.r
self.w = w + 2*self.innerMargin
self.h = h + 2*self.innerMargin
self.r = self.cornerRadius
-- shape
if wo~=self.w or ho~=self.h or ro~=self.r then self:createImg() end
-- shadow position
self:setShadow(self.shadow)
popMatrix() popStyle()
end
function Button:setShadow(s)
self.sx = self.x + s
self.sy = self.y - s
end
function Button:shift(s)
self.shiftX = s
self.shiftY = -s
end
function Button:createImg()
local img
local w,h,r = self.w,self.h,self.r
img = image(w,h)
setContext(img)
resetMatrix() resetStyle() noSmooth() noStroke()
ellipseMode(RADIUS)
fill(255)
rect(r,0,w-2*r,h)
rect(0,r,w,h-2*r)
ellipse(r,r,r)
ellipse(r,h-r,r)
ellipse(w-r,r,r)
ellipse(w-r,h-r,r)
setContext()
self.img = img
end
local d,range = {},{}
d.name = ""
d.txt = ""
d.rx = 300
d.ry = 300
d.fontName = "ArialMT"
d.fontSize = 27
range.fontSize = {min=10,max=50}
d.fontColor=color(255, 255, 255, 255)
d.colorOff = color(31, 42, 95, 255)
d.colorOn=color(21, 25, 178, 255)
d.isPushButton = true
d.visible = true
d.innerMargin = 14
range.innerMargin = {min=0,max=100}
d.cornerRadius = 10
range.cornerRadius = {min=0,max=100}
d.shadow = 5
range.shadow = {min=0,max=10}
d.callback = function(self) print("tap on "..self.name) end
Button.default = d
Button.range = range
-- these keys are the one the user can change
Button.keys = {"txt","fontName","fontSize","innerMargin","fontColor",
"cornerRadius","shadow","colorOff","colorOn","isPushButton"}
function Button:tostring()
local d ={}
local default = Button.default
for key,value in pairs(default) do
if value ~= self[key] and type(value) ~= "function" then
d[key] = self[key]
end
end
local t = {}
t[#t+1] = "Button({ "
for key,value in pairs(d) do
if type(value) == "string" then
t[#t+1] = " " .. key .. "=\"" .. tostring(value) .."\","
elseif type(value) == "userdata" and value.a then
t[#t+1] = " " .. key .. "=color" .. tostring(value) ..","
else
t[#t+1] = " " .. key .. "=" .. tostring(value) ..","
end
end
t[#t+1] = "})"
return table.concat(t,"\n")
end
function Button:setState(choice)
if choice == nil then return self.state end
if choice then self:setOn() else self:setOff() end
end
function Button:setOn()
self.state = true
self.c = self.colorOn
self:shift(self.shadow)
self:setShadow(self.shadow)
if self.isPushButton then
tween.delay(0.5,self.setOff,self) end
end
function Button:setOff()
self.state = false
self.c = self.colorOff
self:shift(0)
self:setShadow(self.shadow)
end
function Button:draw()
if not self.visible then return end
resetMatrix() resetStyle()
noSmooth() noStroke() strokeWidth(0) spriteMode(CORNER)
-- shadow box
if self.shadow ~= 0 then
translate(self.sx, self.sy)
tint(0,0,0,128)
sprite(self.img)
end
-- button box
resetMatrix() translate(self.x+self.shiftX, self.y+self.shiftY)
tint(self.c)
sprite(self.img)
noTint()
-- button text
if self.txt then
font( self.fontName)
fontSize(self.fontSize)
fill(self.fontColor)
textMode(CORNER)
text( self.txt, self.innerMargin, self.innerMargin )
end
end
function Button:touched(t)
if not self.visible then return false end
-- detect if not touched (writen to be the fastest!)
if t.x < self.x or t.x > self.x + self.w
or t.y < self.y or t.y > self.y + self.h
then return false end
-- action when finger up only
if self.edit == nil then self.edit = Buttons.edit end
if self.edit then
if t.state == BEGAN then
self:moveStart(t)
self:setState( not self.state )
elseif t.state == MOVING then
self:move(t)
elseif t.state == ENDED or t.state == CANCELLED then
self:moveEnd(t)
end
else
if t.state == BEGAN then
self:setState( not self.state )
elseif t.state == ENDED then
if self.callback then self:callback() end
end
end
-- tell caller i have been touched
return true
end
function Button:moveStart(t)
self.dx = t.x - self.x
self.dy = t.y - self.y
self.lastx = self.x
self.lasty = self.y
if Buttons.current ~= self then self:parametersShow() end
end
function Button:move(t)
local floor = math.floor
local k = 10
local x,y = self.x,self.y
local newx = floor( (t.x - self.dx)/k +0.5)*k
if newx < 0 then newx = 0 end
if newx + self.w > WIDTH then newx = WIDTH - self.w end
local newy = floor( (t.y - self.dy)/k +0.5)*k
if newy < 0 then newy = 0 end
if newy + self.h > HEIGHT then newy = HEIGHT - self.h end
if newx~=x or newy~=y then
self.x,self.y = newx,newy
self.sx,self.sy = self.sx + (newx-x), self.sy + (newy-y)
if self.x+self.w/2 > WIDTH/2
then self.rx = self.x - WIDTH
else self.rx = self.x
end
if self.y+self.h/2 > HEIGHT/2
then self.ry = self.y - HEIGHT
else self.ry = self.y
end
end
end
function Button:moveEnd(t)
end
function Button:parametersShow()
parameter.clear()
parameter.action("BACK",Buttons.parameterTopMenu)
local demo = function()
output.clear()
print("you can associate a callback function to this button as shown below:")
print(
"\t"..self.name .."= Buttons.list[\"".. self.name .."\"] -- get the button \n" ..
"\t"..self.name ..".callback = function(self) -- define its callback \n" ..
"\t print(\"name: \" .. self.name ) -- button name \n" ..
"\t print(\"label: \" .. self.txt ) -- button label \n" ..
"\t print(\"state: \" , self.state ) -- toggle true/false \n" ..
"\t print(\"visible: \" , self.visible ) -- hide/show \n" ..
"\tend"
)
end
parameter.action("how to use "..self.name,demo)
local del = function() Buttons:delete(self) end
parameter.action("DELETE "..self.name,del)
parameter.action("this style > all buttons",Buttons.applyCurrentButtonToAll)
for i,key in ipairs(self.keys) do
local value = self[key]
local func
if type(value) == "boolean" then
func = function() self:changeBoolean(key) end
elseif type(value) == "string" then
func = function() self:changeString(key) end
elseif type(value) == "number" then
func = function() self:changeNumber(key) end
elseif value.a then
func = function() self:changeColor(key) end
end
if func then
parameter.action(key,func)
end
end
Buttons.current = self
end
function Button:changeBoolean(key)
local value = self[key]
func = function(new) self[key]=new ; self:reset(self) ;
Buttons.saveLast(key,new) end
parameter.clear()
parameter.boolean("button_"..key,value,func)
parameter.action("apply to all",Buttons.applyLastToAll)
self:parameterBackAction()
end
function Button:changeString(key)
local value = self[key]
func = function(new) self[key]=new ; self:reset(self) ;
Buttons.saveLast(key,new) end
parameter.clear()
parameter.text("button_"..key,value,func)
parameter.action("apply to all",Buttons.applyLastToAll)
self:parameterBackAction()
end
function Button:changeNumber(key)
local value = self[key]
func = function(new) self[key]=new ; self:reset(self)
Buttons.saveLast(key,new) end
parameter.clear()
local range = self.range[key]
if range then
parameter.integer("button_"..key,
range.min, range.max, value, func)
end
parameter.action("apply to all",Buttons.applyLastToAll)
self:parameterBackAction()
end
function Button:changeColor(key)
local value = self[key]
func = function(new) self[key]=new ; self:reset(self) ;
Buttons.saveLast(key,new) end
parameter.clear()
parameter.color("button_"..key,value,func)
parameter.action("apply to all",Buttons.applyLastToAll)
self:parameterBackAction()
end
function Button:parameterBackAction()
if not self.backFunc then
self.backFunc = function()
Button.currentKey = nil
self:parametersShow()
if Buttons.autosave then Buttons:save() end
end
end
parameter.action("BACK",self.backFunc)
end
function Button:parameterBefore(key)
if self.firstPass then return end
Button.currentKey = nil
return false
end
-- ###############################################################
-- list of buttons
function Buttons:createButtons()
Buttons:register(
Button({
txt="bigger",
name="button1",
rx=-119,
ry=-78,
})
)
Buttons:register(
Button({
txt="smaller",
name="button2",
rx=-119,
ry=-148,
})
)
Buttons:register(
Button({
txt="rotate",
rx=70,
ry=-78,
isPushButton=false,
name="button3",
})
)
Buttons:register(
Button({
txt="hide",
rx=180,
ry=-78,
isPushButton=false,
name="button4",
})
)
end
-- buttons demo
function setup()
displayMode(FULLSCREEN)
Buttons:editMode(false)
button1= Buttons.list["button1"] -- get the button
button1.callback = function(self) -- define its callback
ballRadius = ballRadius + 10
end
button2= Buttons.list["button2"] -- get the button
button2.callback = function(self) -- define its callback
ballRadius = ballRadius - 10
end
button3= Buttons.list["button3"] -- get the button
button3.callback = function(self) -- define its callback
if self.state then speed = 100 else speed = 0 end
end
button4= Buttons.list["button4"] -- get the button
button4.callback = function(self) -- define its callback
button1.visible = not self.state
button2.visible = not self.state
end
-- ballRadius = ballRadius + 10
-- ballRadius = ballRadius - 10
-- if self.state then speed = 100 else speed = 0 end
-- button3.visible = not self.state
ballRadius = 100
speed = 0
rotAngle = 0
end
function draw()
background(255, 255, 255, 255)
-- your draw here
fill(255, 0, 0, 255)
ellipseMode(RADIUS)
translate(WIDTH/2,HEIGHT/2)
rotAngle = rotAngle + speed*DeltaTime
rotate(rotAngle)
ellipse(0,0,ballRadius)
fill(255, 227, 0, 255)
ellipse(ballRadius/1.2,0,ballRadius/10)
Buttons:draw()
end
function touched(t)
if Buttons:touched(t) then return end
-- your touch here
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment