Has anyone created a toggle switch to use in the full screen viewer. I currently just use the parameter to switch between easy and hard mode.
The code below is my first attempt at a toggle-switch class. It works by swiping horizontally across it, and then it calls the event onChanged
:
Toggle = class()
function Toggle:init(centreX, centreY, value, onChanged, parent)
self.d = 30
self.rect = {
l = centreX - self.d * 1.5,
b = centreY - self.d/2,
w = self.d * 3,
h = self.d
}
self.rect.r = self.rect.l + self.rect.w
self.rect.t = self.rect.b + self.rect.h
self.value = (value == true)
self.onChanged = onChanged
self.parent = parent
self.touchId = nil
end
function Toggle:draw()
local l = self.rect.l
local b = self.rect.b
local r = self.rect.r
local t = self.rect.t
local h = self.rect.h
local d = self.d
local deg2rad = 2 * math.pi/360
local cx1 = l + d/2
local cx2 = r - d/2
local cy = (b + t)/2
pushStyle()
ellipseMode(CENTER)
rectMode(CORNER)
noStroke()
fill(127)
ellipse(cx1, cy, d)
ellipse(cx2, cy, d)
noStroke()
rect(cx1, b, (cx2 - cx1), h)
-- This is my attempt to render two semi-circles.
-- It is not perfect, but I've not yet found a better
-- result
stroke(255)
lineCapMode(PROJECT)
strokeWidth(5)
local ox1 = cx1
local ox2 = cx2
local oy = cy + d/2
for a = 15, 180, 15 do
local dx = d/2 * math.sin(a * deg2rad)
local dy = d/2 * math.cos(a * deg2rad)
local x1 = cx1 - dx
local x2 = cx2 + dx
local y = cy + dy
line(ox1, oy, x1, y)
line(ox2, oy, x2, y)
ox1 = x1
ox2 = x2
oy = y
end
line(cx1, t, cx2, t)
line(cx1, b, cx2, b)
textMode(CENTER)
font("HelveticaNeue")
fontSize(17)
textWrapWidth(0)
noStroke()
if self.value then
fill(0)
text("ON", (cx2 + cx1)/2 - d/2 - 1, cy - 1)
fill(255)
text("ON", (cx2 + cx1)/2 - d/2, cy)
ellipse(cx2, cy, d - 4)
else
fill(0)
text("OFF", (cx2 + cx1)/2 + d/2 - 1, cy - 1)
fill(255)
text("OFF", (cx2 + cx1)/2 + d/2, cy)
ellipse(cx1, cy, d - 4)
end
popStyle()
end
function Toggle:touched(touch)
local x = touch.x
local y = touch.y
local state = touch.state
local id = touch.id
local l = self.rect.l
local r = self.rect.r
local b = self.rect.b
local t = self.rect.t
local d = self.d
local rsq = d*d/4
local cx1 = l + d/2
local cx2 = r - d/2
local cy = (b + t)/2
if (state == BEGAN or state == MOVING) and not self.touchId then
if self.value then
distsq = (x - cx2)*(x - cx2) + (y - cy)*(y - cy)
else
distsq = (x - cx1)*(x - cx1) + (y - cy)*(y - cy)
end
if distsq <= rsq then
self.touchId = id
self.touchOldX = x
self.touchOldY = y
return true
end
return false
end
if state == ENDED and id == self.touchId then
self.touchId = nil
if math.abs(y - self.touchOldY) < self.d then
if self.value then
if (self.touchOldX - x) > self.d * 3 then
self.value = false
if self.onChanged then self.onChanged(self) end
end
else
if (x - self.touchOldX) > self.d * 3 then
self.value = true
if self.onChanged then self.onChanged(self) end
end
end
end
return true
end
return not (not self.touchId)
end
This is an example of its use:
function setup()
local f = function (sender)
print("Toggled to "..tostring(t.value))
end
t = Toggle(WIDTH/2, HEIGHT/2, false, f, nil)
end
function draw()
background(0)
t:draw()
end
function touched(touch)
handled = t:touched(touch)
end
I getting an error on line 8.
I have copied the code above from the forum back into a new project, and I do not get an error. Can you be more specific about the error you get?
nvm it worked. Probably copied it wrong. It looks great. Just wish you could toggle it back to off
You should be able to toggle it to and fro by swiping in the relevant direction each time. The swipe has to pass through the white circle for the switch to ‘capture’ it.
@mpilgrem - groovy. It’s interesting that in your example f can refer to t before it is defined. Lua must have some sort of two pass process when converting to bytecode. I didn’t know you could do that.
I have made some minor changes to the code above. The init()
function did not need to return self
and I intended the event to be called with self
as the sender
.