2D Spinner (3D simulated)

Here’s an example for a 2D spinner selector (3D simulated). Slide your finger on the spinner or the spinner height below the spinner to make a selection. If anyone wants to expand on this, have fun. The name under the red spinner line is saved in the variable self.selected. I show 3 examples. The x, y, width, height, names, fontsize, number of names shown on the slider, background color, and foreground text color can be changed. It gets a little jerky on larger spinners. I’m working on a better way of doing this.

displayMode(FULLSCREEN)

function setup() 
    names1={"0","1","2","3","4","5","6","7","8","9","10","11","12"}
    names2={"red","yellow","green","blue","black",
            "orange","purple","pink","magenta","cyan"}
    names3={"January","February","March","April","May","June",
            "July","August","September","October","November","December"}
    bg1=color(163, 221, 223, 255)       -- background color
    bg2=color(131, 172, 224, 255)
    bg3=color(229, 95, 195, 255)
    fg1=color(255, 0, 17, 255)          -- foreground color
    fg2=color(255, 200, 0, 255)
    fg3=color(255)
    -- see spinner:init for usage
    s1=spinner(200,300,30,100,names1,14,6,bg1,fg1)
    s2=spinner(400,300,70,200,names2,16,10,bg2,fg2)
    s3=spinner(600,300,150,300,names3,26,8,bg3,fg3)
end

function draw()
    background(0)
    s1:draw()
    s2:draw()
    s3:draw()
end

function touched(t)
    s1:touched(t)
    s2:touched(t)
    s3:touched(t)
end

spinner=class()

function spinner:init(x,y,w,h,names,f,nbr,bg,fg)
    self.x=x                    -- x position    
    self.y=y                    -- y position     
    self.width=w                -- width
    self.height=h               -- height
    self.names=names            -- name table
    self.yy=0                   -- temp variable
    self.fontSize=f             -- font size
    self.nbr=(nbr//2)*2         -- approx. number of shown names
    self.bg=bg                  -- background color
    self.fg=fg                  -- foreground text color
    self.selected=""            -- the name under the red spinner line
    self:setup2(self)
end

function spinner:setup2(self)
    local tab={}
    for z=0,179 do
        y=math.cos(math.rad(z))*self.height/2
        table.insert(tab,(self.height-y)-self.height/2)
    end
    local verTab={}
    local texTab={}
    local vv=0
    local v=1/180
    for z=1,#tab-1 do
        -- create vertices table
        table.insert(verTab,vec2(0,tab[z]))
        table.insert(verTab,vec2(self.width,tab[z]))
        table.insert(verTab,vec2(0,tab[z+1]))
        table.insert(verTab,vec2(0,tab[z+1]))
        table.insert(verTab,vec2(self.width,tab[z+1]))
        table.insert(verTab,vec2(self.width,tab[z]))
        -- create texture coordinates table
        table.insert(texTab,vec2(0,vv))
        table.insert(texTab,vec2(1,vv))
        table.insert(texTab,vec2(0,vv+v))
        table.insert(texTab,vec2(0,vv+v))
        table.insert(texTab,vec2(1,vv+v))
        table.insert(texTab,vec2(1,vv))
        vv=vv+v
    end 
    collectgarbage()
    self.m=mesh()   
    self.m.vertices=verTab
    self.m.texCoords=texTab
    self.m:setColors(255,255,255)  
    -- create image for spinner
    local img=image(self.width,self.height)
    local lineDist=self.height/self.nbr
    fontSize(self.fontSize)
    setContext(img)
    background(self.bg)
    fill(self.fg)
    for z=1,#self.names do
        text(self.names[z],self.width/2,(z*lineDist+self.yy)%(lineDist*#self.names))
    end
    local pos=(((self.yy+lineDist/2)//lineDist)%#self.names)
    self.selected=self.names[(#self.names-pos+self.nbr/2-1)%#self.names+1]
    setContext()
    self.m.texture=img
end

function spinner:draw()
    pushMatrix()
    translate(self.x,self.y)
    self.m:draw()
    translate()
    popMatrix()  
    stroke(255, 0, 0, 255)
    strokeWidth(1)
    line(self.x,self.y+self.height/2,self.x+self.width,self.y+self.height/2) 
    -- the following code just shows the self.selected name.
    -- what you do with self.selected depends on your code.
    fill(255)
    fontSize(20)
    text(self.selected,self.x+self.width/2,self.y+self.height+40) 
end

function spinner:touched(t)
    if t.state==MOVING then
        if t.x>self.x and t.x<self.x+self.width and
            t.y>self.y-self.height and t.y<self.y+self.height then
            self.yy=self.yy+t.deltaY  
            self:setup2(self)
        end
    end
end

Use this setup for a date spinner example. There isn’t any code to show the correct number of days for shorter months.

function setup()    
    names1={"1","2","3","4","5","6","7","8","9",
            "10","11","12","13","14","15","16","17","18","19",
            "20","21","22","23","24","25","26","27","28","29","30","31"}
    names2={"2016","2017","2018","2019","2020",
            "2021","2022","2023","2024","2025"}
    names3={"January","February","March","April","May","June",
            "July","August","September","October","November","December"}
    bg1=color(163, 221, 223, 255)       -- background color
    bg2=color(131, 172, 224, 255)
    bg3=color(229, 95, 195, 255)
    fg1=color(255, 0, 17, 255)          -- foreground color
    fg2=color(255, 200, 0, 255)
    fg3=color(255)
    -- see spinner:init for usage
    s1=spinner(350,300,50,200,names1,14,10,bg1,fg1)
    s2=spinner(400,300,70,200,names2,14,10,bg2,fg2)
    s3=spinner(200,300,150,200,names3,14,10,bg3,fg3)
end