Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

List Scroll class demo

edited February 2012 in Code Sharing Posts: 76

I created a ListScroll class to show a list of items such as Text , color or picture. Here is the demo

I do not finish it but I want to do how it can work. Thank you @Mark for your inspiration from Lists program.

Here the source code

--List Scroll class
ListScroll = class()

function ListScroll:init(pos,w,h)
    -- you can accept and set parameters here
    self.pos = pos
    self.width= w
    self.height= h
    self.itemHeight = 0
    self.borderColor = color(100,100,100,255)
    self.borderWidth = 2
    self.backColor = color(255,255,255,255)
    self.sepColor = color(100,100,100,255)
    self.rowColor1 =  color (255,255,255,255)
    self.rowColor2 = color(186, 186, 186, 100)    
    self.allowEdit = false
    self.allowDelete = true
    self.allowInsert = false
    self.multiSelected = false
    self.items = {}
    self.posY = self.pos.y+self.height
    self.prevState = nil
    self.selectedItem = nil
end

function ListScroll:add(i)
    self.itemHeight = i.height
    i.width = self.width
    table.insert(self.items,i)
end

function ListScroll:selectedItem()
    return self.selectedItem
end

function ListScroll:selectedValue()
    if self.selectedItem==nil then 
        return nil 
    end 
    return self.items[self.selectedItem].value
end

function ListScroll:itemCount()
    return #self.items
end 

function ListScroll:draw()
    -- Codea does not automatically call this method
    pushStyle()
        strokeWidth(self.borderWidth)
        fill(self.backColor)
        stroke(self.borderColor)
        rect(self.pos.x,self.pos.y,self.width,self.height)

        clip(self.pos.x,self.pos.y,self.width,self.height)
        for i=1,#self.items do
            strokeWidth(1)
            if i%2==0 then
                fill(self.rowColor1)
            else
                fill(self.rowColor2)
            end 
            self.items[i]:draw(self.pos.x,self.posY-i*self.itemHeight)
        end 
        noClip()
    popStyle()
end

function ListScroll:touched(touch)
    -- Codea does not automatically call this method
    if not (touch.x>=self.pos.x and touch.x<=self.pos.x+self.width and 
           touch.y>=self.pos.y and touch.y<=self.pos.y+self.height) then 
        return 
    end 
    if touch.state==MOVING then
        self.prevState=MOVING
        self.posY = self.posY + touch.deltaY 
        if self.posY>=self.pos.y+self.height+self.itemHeight*(#self.items-1) then
            self.posY=self.pos.y+self.height+self.itemHeight*(#self.items-1)
        end 
    elseif touch.state==ENDED then
        if self.prevState==MOVING then
             if self.posY<self.pos.y+self.height then
                self.posY=self.pos.y+self.height
             end
            self.prevState=nil
        else
            local i = math.ceil((self.posY-touch.y)/self.itemHeight)
            if i<=#self.items then
                self.selectedItem = i
                self.items[i]:touched(touch)
                if not self.multiSelected then
                    for r=1,#self.items do
                        if r ~= i then
                            self.items[r].selected=false
                        end 
                    end 
                end 
            else
                self.selectedItem = nil
            end 
        end 
    end
end

--Color Item
ColorItem = class()

function ColorItem:init(id,c,w,h)
    -- you can accept and set parameters here
    self.pos = vec2(0,0)
    self.id = id
    self.selected = false
    self.selectedColor = color(0,0,0, 100)
    self.width = w
    self.height = h
    self.value = c
end

function ColorItem:draw(x,y)
    -- Codea does not automatically call this method
    self.pos = vec2(x,y)
    pushStyle()
        fill(self.value)
        rect(self.pos.x,self.pos.y,self.width,self.height)
        if self.selected then
            noFill()
            strokeWidth(5)
            stroke(self.selectedColor)
            rect(self.pos.x,self.pos.y,self.width,self.height)
        end 
    popStyle()
end

function ColorItem:touched(touch)
    -- Codea does not automatically call this method
    if self.selected then
        self.selected=false
    else
        self.selected=true
    end
end

--Text Item class
TextItem = class()

function TextItem:init(id,value)
    -- you can accept and set parameters here
    self.pos = vec2(0,0)
    self.id = id
    self.value=value
    self.selected=false 
    self.selectedColor = color(223, 218, 150, 255)
    self.width = 0
    self.height = 0
    self.textColor = color(0,0,0,255)
    self.textAlign=LEFT
    self.fontName = "Courier"
    self.fontSize=24
    font(self.fontName)
    fontSize(self.fontSize)
    _,self.height = textSize(self.fontName)
end

function TextItem:draw(x,y)
    -- Codea does not automatically call this method
    self.pos = vec2(x,y)
    pushStyle()
        strokeWidth(1)
        stroke(stroke())
        if self.selected then
            fill(self.selectedColor)
        end 
        rect(self.pos.x,self.pos.y,self.width,self.height)
        font(self.fontName)
        fontSize(self.fontSize)
        textMode(CORNER)
        textAlign(self.textAlign)
        textWrapWidth(self.width)
        fill(self.textColor)
        text(self.value,self.pos.x+5,self.pos.y)
    popStyle()
end

function TextItem:touched(touch)
    -- Codea does not automatically call this method
    if self.selected then
        self.selected=false
    else
        self.selected=true
    end
end

--Main
-- Use this function to perform your initial setup
function setup()
    print("Hello World!")
    --displayMode(FULLSCREEN)

    listtxt = ListScroll(vec2(50,100),300,600)
    vocab = {"cat","bird","desk","pen","car","dog","rubber","ruler","book","school","bike"}
    for i=1,#vocab do
        itm = TextItem(i,vocab[i])
        listtxt:add(itm)
    end

    cols = {color(255,0,0,255),color(0,0,0,255),color(0,255,0,255),color(0,0,255,255),
            color(255,255,255,255),color(255,255,0,255),color(255,0,255,255),color(0,255,255,255)}
    listcolor = ListScroll(vec2(400,100),300,600)
    for i=1,#cols do
        col = ColorItem(i,cols[i],300,50)
        listcolor:add(col)
    end 

end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(0)

    -- This sets the line thickness
    --strokeWidth(5)

    -- Do your drawing here
    listtxt:draw()
    listcolor:draw()
end

function touched(touch)
    listtxt:touched(touch)
    listcolor:touched(touch)
    --[[
    if touch.state==ENDED then
        print(listtxt:itemCount())
        print(listtxt:selectedValue())
    end 
    --]]
end
Tagged:

Comments

  • Posts: 2,820

    Cool. I'll try it when I get a chance :-)

  • SimeonSimeon Admin Mod
    Posts: 4,986

    Great use of clip(), @sanit. I like the bounce scrolling too.

  • Posts: 1,255

    Hey, that's nice. I really like it, @sanit.

    I hadn't written a line toward solving this issue, and now I don't have to. Thanks!

  • edited February 2012 Posts: 130

    @sanit, I like your ideas. I'll test your example, quickly. =;

  • edited February 2012 Posts: 176

    I am commenting just so I can refer back to this thread easily latter. B-)

    EDIT:
    Wow - I must be slow. I never noticed the Star on the right to bookmark threads.

  • Posts: 2,820

    May I have permission to use this for my Codea Style UI (Yes, I'm still working on it)

  • edited February 2012 Posts: 76

    Please feel free to modify the code. One idea can create another idea. That is the way that sharing code works. I don't think I can finish the full functionality of the list in the near future.



    Here is the list of missing functionality for the ListScroll class as follows

    1. Swiping to the left for deleting an item (show a delete button)

    2. a Bug when swiping down through the outside of the list Scroll area

    3. Double clicking for editing the item (show keyboard)

    4. Smooth scrolling

    5. Add new item in the List

    6. Create a Base class called Item class. All of other item types should subclass from the Item class

    The below code is another sample of ImageItem class

    -- Image Item class
    ImageItem = class()
    
    function ImageItem:init(id,n,w,h)
        -- you can accept and set parameters here
        self.pos = vec2(0,0)
        self.id = id
        self.value = n
        self.selected = false
        self.selectedColor = color(0,0,0, 100)
        self.width = w
        self.height = h
    end
    
    function ImageItem:draw(x,y)
        -- Codea does not automatically call this method
        self.pos = vec2(x,y)
        pushStyle()
            if self.selected then
                noFill()
                strokeWidth(5)
                stroke(self.selectedColor)
                rect(self.pos.x,self.pos.y,self.width,self.height)
            end 
            spriteMode(CORNER)
            sprite(self.value,self.pos.x,self.pos.y,self.width,self.height)
        popStyle()
    end
    
    function ImageItem:touched(touch)
        -- Codea does not automatically call this method
        if self.selected then
            self.selected=false
        else
            self.selected=true
        end
    end
    
    -- Main class using all items such as Text, Color and Image class
    
    -- Use this function to perform your initial setup
    function setup()
        print("Hello World!")
        displayMode(FULLSCREEN)
    
        listtxt = ListScroll(vec2(50,100),300,600)
        --listtxt.multiSelected=true
        vocab = {"cat","bird","desk","pen","car","dog","rubber","ruler","book","school","bike"}
        for i=1,#vocab do
            itm = TextItem(i,vocab[i])
            listtxt:add(itm)
        end
    
        cols = {color(255,0,0,255),color(0,0,0,255),color(0,255,0,255),color(0,0,255,255),
                color(255,255,255,255),color(255,255,0,255),color(255,0,255,255),color(0,255,255,255)}
        listcolor = ListScroll(vec2(400,100),300,600)
        for i=1,#cols do
            col = ColorItem(i,cols[i],300,50)
            listcolor:add(col)
        end 
    
        imgs = {"Planet Cute:Character Boy","Planet Cute:Character Horn Girl",
                 "Planet Cute:Character Princess Girl","Planet Cute:Character Cat Girl"}
    
        listimg = ListScroll (vec2(750,100),200,600)
        for i= 1,#imgs do
            img = ImageItem(i,imgs[i],200,200)
            listimg:add(img)
        end
    
    end
    
    -- This function gets called once every frame
    function draw()
        -- This sets a dark background color 
        background(0)
    
        -- This sets the line thickness
        --strokeWidth(5)
    
        -- Do your drawing here
        listtxt:draw()
        listimg:draw()
        listcolor:draw()
    end
    
    function touched(touch)
        listtxt:touched(touch)
        listimg:touched(touch)
        listcolor:touched(touch)
        --[[
        if touch.state==ENDED then
            print(listtxt:itemCount())
            print(listtxt:selectedValue())
        end 
        --]]
    end
    
  • Posts: 11

    hi, I have a project similar to the List Scroll, and I get a chance to try it.
    The missing functionality (from item1 to item4) works.(item5 - it can't add a item to the table?
    The modified code is below

    --List Scroll class
    ListScroll = class()
    
    function ListScroll:init(pos,w,h)
        -- you can accept and set parameters here
        self.pos = pos
        self.width= w
        self.height= h
        self.itemHeight = 0
        self.borderColor = color(100,100,100,255)
        self.borderWidth = 2
        self.backColor = color(255,255,255,255)
        self.sepColor = color(100,100,100,255)
        self.rowColor1 =  color (255,255,255,255)
        self.rowColor2 = color(186, 186, 186, 100)    
        self.allowEdit = false
        self.allowDelete = true
        self.allowInsert = false
        self.multiSelected = false
        self.items = {}
        self.posY = self.pos.y+self.height
        self.prevState = nil
        self.selectedItem = nil
        
        self.scrollBackTarget = nil
        self.cap = {"Sure","Cancel"}
        self.msgMenu = {}
        for i=1,#self.cap do
            table.insert(self.msgMenu, TextItem(i, self.cap[i]))
            self.msgMenu[i].width = self.width*.5       
            self.msgMenu[i].pos.y = self.posY + self.msgMenu[i].height*.5
            self.msgMenu[i].pos.x = pos.x + self.width*.5*(i-1)
            --self.msgMenu[i].textColor = color(254, 255, 0, 255)
        end
        self.msgMenu["indicate"] = TextItem(#self.msgMenu+1, "indicate")
        self.msgMenu["indicate"].width = self.width      
        self.msgMenu["indicate"].pos.y = self.posY - self.height - self.msgMenu[1].height
        self.msgMenu["indicate"].pos.x = pos.x    
    end
    
    function ListScroll:add(i)
        self.itemHeight = i.height
        i.width = self.width
        table.insert(self.items,i)
    end
    
    function ListScroll:remove(i)
        self.items[i] = self.items[#self.items] 
        self.items[#self.items] = nil
    end
    
    function ListScroll:selectedItem()
        return self.selectedItem
    end
    
    function ListScroll:selectedValue()
        if self.selectedItem==nil then 
            return nil 
        end 
        return self.items[self.selectedItem].value
    end
    
    function ListScroll:itemCount()
        return #self.items
    end 
    
    function ListScroll:draw()
        -- Codea does not automatically call this method
        pushStyle()
            strokeWidth(self.borderWidth)
            fill(self.backColor)
            stroke(self.borderColor)
            rect(self.pos.x,self.pos.y,self.width,self.height)
    
            clip(self.pos.x,self.pos.y,self.width,self.height)
            for i=1,#self.items do
                strokeWidth(1)
                if i%2==0 then
                    fill(self.rowColor1)
                else
                    fill(self.rowColor2)
                end 
                self.items[i]:draw(self.pos.x,self.posY-i*self.itemHeight)
            end 
            noClip()
            
            self:ShowSureBtn()
            self:ScrollSmooth()
            
        popStyle()
    end
    
    function ListScroll:touched(touch)
        if touch.tapCount == 1 then hideKeyboard() end
        if (not isTouched(self.pos, self.width, self.height) 
            or self.scrollBackTarget or self.activedID) then 
            if self.prevState==nil  then
                return 
            end
        end 
    
        local i = math.ceil((self.posY-touch.y)/self.itemHeight)    
        
        if touch.state==MOVING then
            self.prevState=MOVING
            self.posY = self.posY + touch.deltaY 
    
            if self.posY>=self.pos.y+self.height+self.itemHeight*(#self.items-1) then
                self.posY=self.pos.y+self.height+self.itemHeight*(#self.items-1)
            end
            
            if i<=#self.items then
                if touch.deltaX < -self.width/8 then
                    self.activedID = i
                    self.msgMenu["indicate"].value = "確定殺掉" ..tostring(self.items[i].value).."?"
                end 
            end      
        elseif touch.state==ENDED then
    
            if self.prevState==MOVING then
                --if self.itemHeight*#self.items <= self.height then
                    --self.posY = self.pos.y + self.height             
                if self.posY < self.pos.y+self.height then
                    self.scrollBackTarget = self.pos.y+self.height 
                end
                
                self.prevState=nil
    
            else
                if i<=#self.items then
                    self.selectedItem = i
                    self.items[i]:touched(touch)
                    if not self.multiSelected then
                        for r=1,#self.items do
                            if r ~= i then
                                self.items[r].selected=false
                            end 
                        end 
                    end 
                    if touch.tapCount > 1 then showKeyboard() end
                else
                    self.selectedItem = nil
                end 
            end 
        end
    end
    
    
    
    
    
    function ListScroll:ScrollSmooth()
        if self.scrollBackTarget then 
            self.posY = self.posY + 7
            if self.posY >= self.scrollBackTarget then
                self.posY = self.scrollBackTarget 
                self.scrollBackTarget  = nil
            end
        end
    end
            
    function ListScroll:ShowSureBtn()
        if self.activedID then
            for k,item in pairs(self.msgMenu) do            
                self:HndlBtn(item) 
                fill(239, 97, 53, 255)               
                item:draw(item.pos.x,item.pos.y)
            end
            
        end
    end  
    
    function ListScroll:HndlBtn(btn)
        if isTouched(btn.pos, btn.width, btn.height ) then
            if btn.value == "Sure" then
                self:remove(self.activedID)
            end
            self.activedID = nil 
        end                    
    end
    
    function isTouched(pos, width, height )
        return CurrentTouch.x>pos.x and CurrentTouch.x<pos.x+width 
            and CurrentTouch.y>pos.y and CurrentTouch.y<pos.y+height
    end
    
Sign In or Register to comment.