Francisco Sant'Anna

A structured main menu: full code

@_fsantanna

This is the full commented code for the structured main menu:

-- The language still misses very basic functionality like primitive integers
-- and strings. Hence, the code relies on native C symbols, which are
-- prefixed with an underscore (e.g., `_255` and `_("Story")`).
-- `Pico` is a simple graphical library based on SDL.

-- Includes auxiliary files
^"prelude.ceu"
^"int.ceu"
^"float.ceu"
^"pico.ceu"

-- Sets the initial window properties
output Pico.Set.Title _("Pingus")
output Pico.Set.Size [_641,_481]
output Pico.Set.Zoom [_100,_100]
output Pico.Set.Grid _0
output Pico.Set.Color.Clear [_0,_0,_0,_255]
output Pico.Clear
output Pico.Set.Auto _0

-- Menu enumeration
type Menu = <Story=(),Editor=(),Levelsets=(),Options=(),Exit=()>

-- Task to show a single button:
--  - receives point and label to show
--  - terminates on a mouse click
task menu_button: [pos:Point,lbl:_(char*)] -> () -> () {
    var size: Size  -- get dimensions to detect click
    output Pico.Get.Size.Image [/size, _("data/images/menuitem.png")]

    -- task to show itself on every Draw event
    spawn {
        every evt?Draw {
            -- draw image with label on top
            output Pico.Draw.Image [arg.pos, _("data/images/menuitem.png")]
            output Pico.Set.Font   [_("data/fonts/film-cryptic/Filmcryptic.ttf"),_45]
            output Pico.Draw.Text  [arg.pos, arg.lbl]
        }
    }

    -- awaits a mouse click inside its region to terminate
    await evt?Mouse?Button?Down until isPointVsRect [pos,[arg.pos,size]]
        where {
            var pos = evt!Mouse!Button!Down.pos
        }
}

-- Task to show the main menu:
--  - spawns a `menu_button` task for each button in the menu
--  - terminates when any button is clicked
--  - returns the `Menu` enumeration associated with the click
task main_menu: () -> () -> Menu {
    -- spawns multiple tasks in parallel to wait for the buttons
    par {
        -- spawns and awaits each button
        await spawn menu_button [[_(-125),_(  35)], _("Story")]
        -- returns the associated enumeration
        return Menu.Story
    } with {
        await spawn menu_button [[_( 125),_(  35)], _("Editor")]
        return Menu.Editor
    } with {
        await spawn menu_button [[_(-125),_( -35)], _("Levelsets")]
        return Menu.Levelsets
    } with {
        await spawn menu_button [[_( 125),_( -35)], _("Options")]
        return Menu.Options
    } with {
        await spawn menu_button [[_(   0),_(-105)], _("Exit")]
        return Menu.Exit
    }
}

-- Main application:
--  - a loop that alternates between the menu and the chosen button
spawn {
    loop {
        -- spawns the main menu and awaits its termination
        var opt = await spawn main_menu ()

        -- maps the chosen button to a label to show next
        var lbl: _(char*) = ifs {
            opt ? Story     { _("Story")     }
            opt ? Editor    { _("Editor")    }
            opt ? Levelsets { _("Levelsets") }
            opt ? Options   { _("Options")   }
            opt ? Exit      { _("Exit")      }
        }

        -- shows and awaits the chosen button in the center of the screen
        await spawn menu_button [[_0,_0], lbl]
    }
}

-- Enters the engine main loop.
-- Now the application is entirely reactive.
-- In this code, only the individual buttons (`menu_button` task) react to
-- events (evt?Draw and evt?Mouse).
call pico_loop ()

Comment on @_fsantanna.