Toggle Switch

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.