Howdy, Stranger!

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

Run Projects from a menu

dave1707dave1707 Mod
in Code Sharing Posts: 7,155

@CodeLearnerMike You might find this interesting. I wrote this because of your Run Multiple Tabs discussion.

Here’s something I threw together to run different projects from a menu. I didn’t put a lot of time into this, so it’s kind of limited. This code example will let you run different Codea projects from a menu screen. When you're running a project, to return to the Main Menu, press the Main Menu parameter button. You might have to drag open the parameter pane if a project is in fullscreen mode. I don’t have a use for this code which is why I haven’t put a lot into it. Some of the projects that can’t use this are:

  1. Projects that define variables before setup() runs.
  2. Projects that call code before setup() runs.
  3. Projects that call code from another project (calling universal in some of the Codea examples)
  4. Other things that I haven’t found yet.
function setup()
    rectMode(CENTER)
    st1="if not reStarting then reStarting=true setup() end"
    st2="parameter.action('Main Menu',function() restart() end)"
    proj={"Exit","Gravity","Shaders","Roller Coaster","Multi Touch","Ellipse Modes"}
end

function draw()
    background(157, 157, 181, 255)
    for a,b in pairs(proj) do
        fill(0, 206, 254, 255)
        rect(WIDTH/2,100+80*a,120,50)
        fill(247, 22, 22, 255)        
        text(b,WIDTH/2,100+80*a)
    end
end

function touched(t)
    if t.state==BEGAN then
        button(t)
        if str~="" then
            a,b=string.find(str,"function setup()",1,true)
            str=string.sub(str,1,b)..st2..string.sub(str,b+1,#str)
            a,b=string.find(str,"function draw()",1,true)
            str=string.sub(str,1,b)..st1..string.sub(str,b+1,#str)
            loadstring(str)()
        end
    end
end

function button(t)
    for a,b in pairs(proj) do
        str=""
        if t.x>WIDTH/2-60 and t.x<WIDTH/2+60 and t.y>50+a*80 and t.y<150+a*80 then
            if b=="Exit" then 
                close()
            else
                lst=listProjectTabs(b)
                for c,d in pairs(lst) do
                    str=str..readProjectTab(b..":"..d)
                end
                return(str)
            end
        end
    end
end

Comments

  • dave1707dave1707 Mod
    Posts: 7,155

    Here’s another version. I removed the Main Menu parameter button. To return to the Main Menu, just press the restart button at the bottom of the print window.

    displayMode(STANDARD)
    
    function setup()
        rectMode(CENTER)
        st1="if not reStarting then reStarting=true setup() end"
        proj={"Exit","00b","Gravity","Shaders","Roller Coaster","Multi Touch","Ellipse Modes"}
    end
    
    function draw()
        background(157, 157, 181, 255)
        for a,b in pairs(proj) do
            fill(0, 206, 254, 255)
            rect(WIDTH/2,100+80*a,120,50)
            fill(247, 22, 22, 255)        
            text(b,WIDTH/2,100+80*a)
        end
    end
    
    function touched(t)
        if t.state==BEGAN then
            button(t)
            if str~="" then
                a,b=string.find(str,"function draw()",1,true)
                str=string.sub(str,1,b)..st1..string.sub(str,b+1,#str)
                loadstring(str)()
            end
        end
    end
    
    function button(t)
        for a,b in pairs(proj) do
            str=""
            if t.x>WIDTH/2-60 and t.x<WIDTH/2+60 and t.y>50+a*80 and t.y<150+a*80 then
                if b=="Exit" then 
                    close()
                else
                    lst=listProjectTabs(b)
                    for c,d in pairs(lst) do
                        str=str..readProjectTab(b..":"..d)
                    end
                    return(str)
                end
            end
        end
    end
    
  • edited November 8 Posts: 15

    @dave1707 Thanks, I’ve learned something new “readProjectTab” that’s what I was looking for, where could I find more commands like that to learn? Sorry if I’m asking too much but do you think you could make this code run a new tab running the AR example? I tried to implement the readProjectTab function but every method I tried I got errors.

    --# AR
    
    
    function setup()
        -- Create a new craft scene
        scene = craft.scene()
        scene.sun:get(craft.light).intensity = 0.7
    
        if craft.ar.isSupported then
            -- Enable AR session
            scene.ar:run()
    
            -- Keep a list of detected planes
            planes = {}
    
            -- Option to turn plane detection on and off
            parameter.boolean("PlaneDetection", true, function(b)
                scene.ar.planeDetection = b
            end)
    
            -- Option to draw any detected planes using camera rendering mask
            parameter.boolean("DrawPlanes", true, function(b)
                local c = scene.camera:get(craft.camera)
                if b then
                    c.mask = ~0
                else
                    c.mask = 1
                end
            end)
    
            parameter.boolean("DrawPointCloud", true)
    
            local grid = readImage("Project:GridWhite")
    
            scene.ar.didAddAnchors = function(anchors)
                for k,v in pairs(anchors) do
                    local p = scene:entity():add(Plane, v, grid)
                    planes[v.identifier] = p
                end
            end
    
            scene.ar.didUpdateAnchors = function(anchors)
                for k,v in pairs(anchors) do
                    local p = planes[v.identifier]
                    p:updateWithAnchor(v)
                end
            end
    
            scene.ar.didRemoveAnchors = function(anchors)
                for k,v in pairs(anchors) do
                    local p = planes[v.identifier]
                    p.entity:destroy()
                    planes[v.identifier] = nil
                end
            end   
    
            trackingState =
            {
                [AR_NOT_AVAILABLE] = "Not Available",
                [AR_LIMITED] = "Limited",
                [AR_NORMAL] = "Normal"
            }
    
            cross = image(16,16)
            setContext(cross)
            pushStyle()
            fill(255, 198, 0, 255)
            noStroke()
            rectMode(CENTER)
            rect(cross.width/2, cross.height/2, 3, cross.height)
            rect(cross.width/2, cross.height/2, cross.width, 3)
            popStyle()
            setContext()
    
        end
    
    end
    
    function update(dt)
        scene:update(dt)   
    end
    
    -- Called automatically by codea 
    function draw()
        update(DeltaTime)
    
        -- Draw the scene
        scene:draw()    
    
        local status = nil
        if craft.ar.isSupported then
            status = trackingState[scene.ar.trackingState]
    
            if DrawPointCloud then
                local c = scene.camera:get(craft.camera)
                for k,v in pairs(scene.ar.points) do
                    local p = c:worldToScreen(v)
                    sprite(cross, p.x, p.y)
                end
            end
        else
            status = "AR Not Supported"
        end
        fill(255, 255, 255, 255)
        text(status, WIDTH/2, HEIGHT - 50)
    
    end
    
    function touched(touch)
        if craft.ar.isSupported and touch.state == BEGAN then
            local results = scene.ar:hitTest(
                vec2(touch.x, touch.y),
                AR_EXISTING_PLANE_CLIPPED)
    
            for k,v in pairs(results) do
                local e = scene:entity()
                local cube = e:add(Cube, v.position + vec3(0,0.5,0), 0.1)
                break
            end
        end
    end
    
    --# Cube
    
    Cube = class()
    function Cube:init(entity,position, size)
    self.entity = scene:entity()
    self.entity.model = craft.model()
    self.entity.position = position
    self.entity.scale=vec3(.5,.5,.5)*size
    self.entity:add(craft.rigidbody, STATIC, 1)
    
    end 
    --# Plane
    Plane = class()
    
    function Plane:init(entity, anchor, map)
        self.entity = entity
        self.entity.model = craft.model.plane(vec2(1,1))
        self.entity:get(craft.renderer).mask = 1<<2
    
        local mat = craft.material("Materials:Basic")
        mat.map = map
        mat.blendMode = NORMAL
        mat.diffuse = color(120, 200, 255)
        self.entity.material = mat
    
        -- Collisions   
        self.entity:add(craft.rigidbody, STATIC)
        self.entity:add(craft.shape.box, 
            vec3(1,0.1,1), vec3(0,-0.05,0))
    
        self:updateWithAnchor(anchor, true)
    end
    
    function Plane:updateWithAnchor(anchor, s)
        self.entity.position = anchor.position
        self.entity.scale = anchor.extent + vec3(0,1,0)
        self.entity.rotation = anchor.rotation 
        self.entity.material.offsetRepeat = 
            vec4(0,0,anchor.extent.x, anchor.extent.z)   
    end
    
    --# Main
    
    
    function setup() 
        func=menu    -- start screen
    
        buttonTab={}    -- buttons table
    
        -- buttons that show on the menu screen
        table.insert(buttonTab,button(350,600,100,50,"Screen 1",menu,screen1))
        table.insert(buttonTab,button(350,500,100,50,"Screen 2",menu,screen2))
        table.insert(buttonTab,button(350,400,100,50,"Screen 3",menu,screen3))
        table.insert(buttonTab,button(700,50,100,50,"EXIT",menu,close))
    
        -- buttons that show on screen1
        table.insert(buttonTab,button(350,600,150,50,"Google",screen1,url1))
        table.insert(buttonTab,button(350,500,150,50,"twolivesleft",screen1,url2))
        table.insert(buttonTab,button(350,100,150,50,"Menu",screen1,menu))
    
        -- buttons that show on screen2
        table.insert(buttonTab,button(350,600,150,50,"map quest",screen2,url3))
        table.insert(buttonTab,button(350,100,150,50,"Menu",screen2,menu))
    
        -- buttons that show on screen3
        table.insert(buttonTab,button(350,600,150,50,"amazon",screen3,url4))    
        table.insert(buttonTab,button(350,100,150,50,"Menu",screen3,menu))
    end
    
    function draw()
        background(40, 40, 50)
        func()    -- call the function set by the button
    end
    
    function touched(t)    -- check if a button was pressed
        if t.state==BEGAN then
            for a,b in ipairs(buttonTab) do
                if b:touched(t) then
                    break
                end                
            end
        end
    end
    
    function menu()
        background(58, 97, 136, 255)
        fontSize(30)
        text("Menu Screen",350,700)
        drawButtonTab()
    end
    
    function screen1()
        background(101, 43, 43, 255)
        fontSize(30)
        text("Screen 1",350,700)
        drawButtonTab()
    end
    
    function screen2()
        background(110, 165, 74, 255)
        fontSize(30)
        text("Screen 2",350,700)
        drawButtonTab()
    end
    
    function screen3()
        background(150, 144, 44, 255)
        fontSize(30)
        text("Screen 3",350,700)
        drawButtonTab()
    end
    
    function url1()
        openURL('http://www.google.com',true)
        func=screen1    -- return to screen1
    end
    
    function url2()
        openURL('http://twolivesleft.com',true)
        func=screen1    -- return to screen2
    end
    
    function url3()
        openURL('http://www.mapquest.com',true)
        func=screen2    -- return to screen3
    end
    
    function url4()
        readProjectTab("AR")
        func=screen3    -- return to screen4
    end
    
    function drawButtonTab()    -- draw selected buttons from button table
        fontSize(20)
        for a,b in ipairs(buttonTab) do
            b:draw()
        end
    end    
    
    button=class()
    
    function button:init(x,y,w,h,name,screen,func)
        self.x=x    -- x position
        self.y=y    -- y position
        self.w=w    -- width
        self.h=h    -- height
        self.name=name    -- name to put on the button 
        self.screen=screen -- screen to draw the button on
        self.func=func    -- function to call when the button is pressed
    end
    
    function button:draw()
        if func==self.screen then    -- draw the button
            sprite("Cargo Bot:Dialogue Button",self.x,self.y,120)
            fill(255, 0, 0, 255)
            text(self.name,self.x,self.y)
        end
    end
    
    function button:touched(t)
        if func==self.screen then    -- only check current screen button 
            if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
                t.y>self.y-self.h/2 and t.y<self.y+self.h/2 then
                    func=self.func else for function url4 do readProjectTab"AR"
                    return true
            end
            return false
        end
    end
    
  • edited November 8 Posts: 1,014

    @CodeLearnerMike - not a mod so I can’t correct but you need to place your ~~~ characters before code and after all code, otherwise a bit messy. Check with the preview option on the comment box before posting.

    I get an error from the line

    Function=self.func else function url4 do readProjectTab”AR”
    

    Playing around with it I can get it to run but the code has lost functionality.

  • dave1707dave1707 Mod
    Posts: 7,155

    @CodeLearnerMike I added ~~~ before and after your code so it displays correctly. As for commands, at the top of the forum is a link for Reference. I suggest you look thru that to see what commands are available and what they do.

  • Posts: 1,014

    @dave1707 - another thank you I owe you. Ages ago I posted that Codea would benefit from a chain command (like in many basics) so that you could run separate parts of a project. I didn’t realise you could do it this way.

    Do you know if memory is cleared when you run separate projects, if you have graphic intensive apps and low internal memory it could be important.

    Other issue, I added a few more projects from the examples and my own projects. They all ran except for ones I had stored in a directory. I couldn’t get projects to run by adding the path. This is odd because the examples in your menu are all in an example folder on my iPad. Weird !!!

  • dave1707dave1707 Mod
    edited November 8 Posts: 7,155

    @Bri_G I think memory would be cleared because of the restart command. You could try adding collectgarbage("count") to show the memory size. I’m not sure of all the restrictions that my code has. It was a quick try and things kind of worked. I didn’t try a lot of different projects to see which ones worked and what was different with the one that didn’t.

  • dave1707dave1707 Mod
    Posts: 7,155

    @CodeLearnerMike You can’t stick multiple projects into 1 project and expect it to work. In your above code, you have 2 setup(), 2 draw() and 2 touched() functions. The 2nd of each of those functions will override the functions in the first code which means it’s totally useless. The menu part might work somewhat, but the AR code won’t. There’s no point in even trying to fix it.

  • @dave1707 ok I can understand that, if I got more questions can I message you?

  • @Bri_G thanks for giving it a try, what did you change that allowed it to run?

  • dave1707dave1707 Mod
    Posts: 7,155

    @CodeLearnerMike @Bri_G probably changed the code like this

       func=self.func 
        --else for function url4 do readProjectTab"AR"
       return true
    

    which means the menu part of the code worked until you selected Amazon at which point it tried to run readProjectTab(“AR”) which is an invalid tab. I suggest you look thru the reference and read the explanations for the commands you use. readProjectTab() will read the contents of the tab named between the () and return a string.

  • Posts: 1,014

    @CodeLearnerMike - the changes I made are below only partially resolved the problem, it allowed me to access a couple of web pages. Hope this helps you.


    function button:touched(t) if func==self.screen then -- only check current screen button if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and t.y>self.y-self.h/2 and t.y<self.y+self.h/2 then func=self.func else -- for function url4 -- end do readProjectTab"AR" return true end end return false end end
Sign In or Register to comment.