My toggle class [HUGE UPDATE, looks like iOS 7]

I recently saw a picture of what all the iOS 7 UI elements would look like, and i needed to update my toggle class to match the look and feel. Enjoy the new version:



--# Main
-- iOS 7 UI

-- Use this function to perform your initial setup
function setup()
    saveProjectInfo("Author", "Jordan Arenstein")
    saveProjectInfo("Description", "iOS 7 style UI")
    t = Toggle(WIDTH / 2, HEIGHT / 2, "bool")
end

-- This function gets called once every frame
function draw()
    background(0, 0, 0, 255) 
    t:draw()
end

function touched(touch)
    t:touched(touch)
end
--# Toggle
local vS = [[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec2 texCoord;
varying highp vec2 tC;
void main()
{
    tC = texCoord;
    gl_Position = modelViewProjection * position;
}
]]

local fS = [[
precision highp float;
varying highp vec2 tC;
uniform highp vec4 bg; // Background color
uniform highp vec4 s; // Stroke Colour
uniform highp float sw;
uniform highp vec4 t; // Toggle Colour
uniform highp vec2 d; // Dimensions
uniform highp float v; // Value from false (0) to true (1)
uniform highp vec4 b;
uniform highp float bw;
highp float r = (d.y / 2.)/ d.x; // Horizontal Radius
highp vec2 ls = vec2(r, .5); // Left Side
highp vec2 rs = vec2(1. - r, .5); // Right Side
highp vec2 lsd = tC - ls;
highp vec2 rsd = tC - rs;
highp vec2 vd = tC - vec2(r + (1. - r * 2.) * v, .5);
void main()
{
    if (
        (vd.x * vd.x) / (r * r) + (vd.y * vd.y) / 0.25 <= 1.
    ) {
        if (
            (vd.x * vd.x) / (r * r) + (vd.y * vd.y) / 0.25 <= 1. - sw / (d.y / 2.)
        ) {
            gl_FragColor = t;
        } else {
            gl_FragColor = mix(s, bg, (vd.x * vd.x) / (r * r) + (vd.y * vd.y) / 0.25);
        }
    } else if (
        tC.x > r && tC.x < 1. - r
    ) {
        if (abs(tC.y - 0.5) * 2. <= 1. - bw / (d.y * 2.) * 2.) {
            gl_FragColor = bg;
        } else {
            gl_FragColor = mix(b, bg, abs(tC.y - 0.5) * 2.);
        }
    } else if (
        (lsd.x * lsd.x) / (r * r) + (lsd.y * lsd.y) / 0.25 <= 1.
    ) {
        if ((lsd.x * lsd.x) / (r * r) + (lsd.y * lsd.y) / 0.25 >= 1. - bw / (d.y / 2.)) {
            gl_FragColor = mix(b, bg, (lsd.x * lsd.x) / (r * r) + (lsd.y * lsd.y) / 0.25);
        } else {
            gl_FragColor = bg;
        }
    } else if (
        (rsd.x * rsd.x) / (r * r) + (rsd.y * rsd.y) / 0.25 <= 1.
    ) {
        if ((rsd.x * rsd.x) / (r * r) + (rsd.y * rsd.y) / 0.25 >= 1. - bw / (d.y / 2.)) {
            gl_FragColor = mix(b, bg, (rsd.x * rsd.x) / (r * r) + (rsd.y * rsd.y) / 0.25);
        } else {
            gl_FragColor = bg;
        }
    } else {
        discard;
    }
}
]]
Toggle = class()

function Toggle:init(x, y, name, callback, initial)
    if callback then
        self.callback = callback
        self.bool = initial
        self.name = name
        _G[self.name] = self.bool
    elseif initial ~= nil then
        if type(initial) == "function" then
            self.callback = initial
            self.name = name
            _G[self.name] = _G[self.name] or true
            self.bool = _G[self.name]
        else
            self.bool = initial
            self.callback = function () end
            self.name = name
            _G[self.name] = self.bool
        end
    else
        self.name = name
        self.callback = function () end
        _G[name] = _G[name] or true
        self.bool = _G[name]
    end
    self.selected = nil
    self.tapped = false
    
    self.x, self.y = x, y
    self.w, self.h = 50, 30
    self.p = (self.bool and 1 or 0)
    local w, h = self.w / 2, self.h / 2
    self.colors = {}
    self.colors.on = color(83, 215, 105, 255)
    self.colors.off = color(255, 255, 255, 255)
    self.mesh = mesh()
    self.mesh.shader = shader(vS, fS) 
    self.mesh.shader.d = vec2(w, h)
    self.mesh.shader.bg = self.colors.on
    self.mesh.shader.t = self.colors.off
    self.mesh.shader.s = color(0, 0, 0, 255)
    self.mesh.shader.sw = 2
    self.mesh.shader.b = color(229, 229, 229, 255)
    self.mesh.shader.bw = 3
    self.mesh.shader.v = 0.5
    
    self.mesh.vertices = {
        vec2(-w, -h), vec2(-w, h), vec2(w, h),
        vec2(-w, -h), vec2(w, -h), vec2(w, h),
    }
    self.mesh.texCoords = {
        vec2(0, 0), vec2(0, 1), vec2(1, 1),
        vec2(0, 0), vec2(1, 0), vec2(1, 1)
    }
    self.mesh:setColors(255, 255, 255, 255)
end

function Toggle:draw()
    self.mesh.shader.v = self.p
    self.mesh.shader.bg = self.colors.on:mix(self.colors.off, self.p)
    self.mesh.shader.b = self.colors.on:mix(self.colors.off, self.p * .8)
    pushMatrix()
        translate(self.x, self.y)
        self.mesh:draw()
    popMatrix()
end


function Toggle:touched(touch)
    if math.abs(touch.x - self.x) < self.w and math.abs(touch.y - self.y) < self.h and touch.state == BEGAN and self.selected == nil then
        self.selected = touch.id
        self.tapped = true
    elseif self.selected and touch.id == self.selected then
        if touch.state == MOVING then
            self.p = math.max(math.min(1, self.p + touch.deltaX / self.w), 0)
            self.tapped = false
        end
        if touch.state == ENDED then
            self.selected = nil
            if self.tapped then
                self:switch()
                return
            end
            if self.bool then
                if self.p < 1 - 1 / 6 then
                    self:switch()
                else
                    self:reset()
                end
            else
                if self.p > 1 / 6 then
                    self:switch()
                else
                    self:reset()
                end
            end
        end
    end
end

function Toggle:switch()
    self.bool = not self.bool
    _G[self.name] = self.bool
    self.callback(self.bool)
    tween(0.25, self, { p = (self.bool and 1 or 0) })
end

function Toggle:reset()
    tween(0.25, self, { p = (self.bool and 1 or 0) } )
end