Howdy, Stranger!

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

Seeing the light, using SODA

edited September 2016 in Code Sharing Posts: 1,799

I have long been ashamed of the clunky look of the buttons I made for my daughters' app (DoubleChoose, available on the App Store!).

I have also long been trying to write my own button API, and in the process somehow decided to rewrite the whole darn app from scratch.

Mercifully, some sanity has descended.

There's no need to rewrite the app. The app works. And @yojimbo2000 has already written the very best Codea button API I have ever seen. In fact, it's the very best third-party Codea API that I've seen, period. It's called SODA (you can find it by searching "soda" on the forums).

So thanks @yojimbo2000, for making this incredible thing.

That said, I'm having a really pretty terrible bug: when I run SODA as a dependency, the Codea controls do not appear on screen, nor are they invisible but functional. To stop a running project, I have to leave the app, terminate it, and restart it. Needless to say, this is not workable long-term.

Here is my "main" class, which is just copied directly from the template:

-- Main
saveProjectInfo( "Description", "Two-choice Adventure Games by Rosie and Charlotte." )

-- Soda

-- Use this as a template for your projects that have Soda as a dependency. 

function setup()
    saveProjectInfo("Description", "Soda v"..Soda.version) 
    -- demo1() --do your setting up here

function draw()
    --do your updating here

function drawing(breakPoint) 
    --in order for gaussian blur to work, do all your drawing here
    background(40, 40, 50)
    sprite("Cargo Bot:Game Area", WIDTH*0.5, HEIGHT*0.5, WIDTH, HEIGHT)

--user inputs:

function touched(touch)
   if Soda.touched(touch) then return end
    --your touch code goes here

function keyboard(key)

function orientationChanged(ori)

--measure performance:


function profiler.init(quiet)    
    if not quiet then"profiler.fps")"profiler.mem")

function profiler.draw()
    profiler.del = profiler.del +  DeltaTime
    profiler.c = profiler.c + 1
    if profiler.c==10 then
        profiler.mem=collectgarbage("count", 2)

Right now, I've replaced the DoubleChoose app's own "main" tab with this, just to get started with it.

I have no idea what's causing this problem, but having come to my senses about not reinventing the wheel, I hope I can get the awesome already-invented wheel to roll.



  • IgnatzIgnatz Mod
    Posts: 5,396

    Just a quick suggestion. Maybe Soda is somehow disabling the displayMode(overlay) command. What happens if you put it in setup, so it runs after Soda loads?

  • edited September 2016 Posts: 1,799
    I'm not at home so I can't check, but wouldn't such an issue show up on the regular demo as well as when used as a dependency? This only shows up when I'm running the demo as a dependency.
  • Posts: 2,020

    Hey @UberGoober good to see you on the forums again! Glad you're enjoying Soda! I liked your supersimplebuttons too.

    Re your issue above, that's really weird, displayMode is only called from your main file there. Are you sure you don't have FULLSCREEN_NO_BUTTONS somewhere else in your code? In any case, it should be possible to bring the Codea buttons back a number of different ways. The easiest way is to do a partial gesture, such as pulling one of the iOS control panels from the top or bottom of the screen then releasing it, or (if you have multitasking iOS gestures on), doing a partial 4-finger swipe then releasing it. Do you have the a reasonably recent version of Soda? Could you look at the Soda.version variable in the Soda tab? Does it say 0.7? Also, I don't see the behaviour you described in the Soda thread, ok, cancel and X all close the demo windows for me, which makes me wonder whether you have a different version.

  • Posts: 1,799

    @yojimbo2000 thanks for the diagonistic suggestions!

    • I totally had FULLSCREEN_NO_BUTTONS set, d'oh!
    • I can't believe I didn't think to search for that. It was in a block of stuff I thought I had all commented out.
    • Thanks for the tips on getting the buttons back.
    • I'm running Soda 0.7, and I just verified that I'm running the latest Codea as well.
    • Any thoughts on how to debug the OK button thing? It happens directly in the SODA project, it's not an artifact of dependency.
    • Thanks for the welcome back! Life keeps me pretty busy but I usually get back to my Codea projects when I'm on a family vacation or holidy of some kind.
  • Posts: 1,799
    @yojimbo2000 after investigating the problem a little, it looks like there's something up with coroutine. In my setup, I have about six or seven calls to coroutine, and only three of them fire. Is there something going on in SODA that might be interrupting them?
  • Posts: 2,020

    No, Soda doesn't use coroutines. What are you using them for? Kind of unusual to be calling them within setup. The usual use case is for "concurrency" of intensive tasks (though not true concurrency, just frequent interruption) over several frames, so normally you'd resume the coroutines in the draw loop somewhere

  • Posts: 1,799
    I'm using "setup" loosely. The coroutines do indeed start at the end of the setup routine.

    To tell the truth I forget why I implemented them, I think it may have been done at a point where I was loading all my images over the web, which could take a while. It may also have been just to get some configuration logic out of the draw routine, while still managing drawing stuff to the screen.

    Not entirely sure, but also not sure it matters that much, because it without SODA, it's working. So something about SODA is interrupting it. If you're suggesting "just rip out the coroutines" as a Gordian knot style fix, I suppose that's the nuclear option. Would much rather just fix what's going wrong though.
  • Posts: 2,020
    Can you post some code?
  • edited November 2016 Posts: 1,799
    Hi! Okay... I'm ashamed to admit that I figured out the main problem, and it's that I had commented out some crucial command flow code. The code that wasn't running wasn't being called. Sad trumpet sound here.

    So I've finally got my first SODA button appearing on screen. Yay!

    Now I've got two actual buggish type things.

    1) I'm trying to simulate that info circle icon that's everywhere nowadays. Here's my code:

    (I can't get code markup to appear correctly)

    title = "i",
    style = {shape = {fill = color(0, 0, 0, 0), stroke = "midGrey", strokeWidth = iStrokeWidth}, text = {fontSize = iFontSize, font = "Baskerville-BoldItalic", fill="midGrey"},
    highlight = {
    text = {fontSize = iFontSize, font = "Baskerville-BoldItalic", fill="white"},
    shape = {fill = "midGrey"}
    } },
    shape = Soda.ellipse,
    x = 20, y = 20, w = iCircleSize, h = iCircleSize

    (It's terribly indented I know, that's the sign of code in progress.)

    This creates a bold italic "i" inside a circle. The problem is that the "i" is clipped on the right side. It looks like something's cutting off about a fourth of the dot of the i.

    2: For some odd reason I can't use calculated variables for the x and y values. If the above code is slightly modified to:

    local iOffset = HEIGHT * 0.1
    x = iOffset, y = iOffset

    The button doesn't appear **at all.** That exact change, with no others, makes it vanish.

    What's even odder is that it has to be a *calculated* variable. If instead of the above iOffset is defined like this:

    local iOffset = 40
    x = iOffset, y = iOffset
    ~~~ does appear!

    Could this have something to do with Lua's recent introduction of different types of numbers? You know, how now there are ints and floats, whereas there used to be just floats, and the ints and floats can't be used interchangeably, breaking some legacy code?

    @yojimbo2000 , any help you can offer is greatly appreciated.
  • AnatolyAnatoly Mod
    Posts: 893

    I'm the 200ths view. Also, add code blocks above ^. They are wrong and not working

  • edited November 2016 Posts: 1,799

    Here is a link to a screenshot of how the clipping looks: i.jpeg?dl=0
  • Posts: 2,020

    @UberGoober have you checked this isn't an issue with Codea's text rendering? Try just printing the italic i, not in Soda, to see if it clips. Also, try adding a space after the i to see if that helps.

  • Posts: 2,020

    It's 3 tildes (not 4) ~~~ for a codeblock in the forum btw

  • Posts: 2,020

    Where is this code called local iOffset = HEIGHT * 0.1 ? HEIGHT behaves unpredictably if you call it outside of any code block (ie at compile time)

  • edited November 2016 Posts: 1,799
    Switched to 3 tildes--still not showing up correctly.
    It's not working here either! What up??
  • Posts: 1,799
    I'm referencing HEIGHT inside a function--does that count as "inside a code block" for this purpose?

    It doesn't matter to the bug, though--whether it references HEIGHT or not, if iOffset is set as the result of multiplying or dividing another variable in any way, it doesn't work.

    It works if set with a value directly, and no other time.
  • Posts: 1,799
    Space after the i! That worked! @yojimbo2000 , you know your anchovies!
  • Posts: 1,799
    Okay, so I'm trying to make an almost-full-screen information window, which is mainly a bunch of text, but I want the text body centered vertically in the window. It looks to me like I have to create a TextScroll with the text, as a child of a TextWindow, and programmatically place the TextScroll in the middle of the window vertically.

    @yojimbo2000 do I have that right?
  • Posts: 1,799

    This is my code for the info window, it is crashing.

            local window = Soda.TextWindow{
                title = "",
                close = true,
                blurred = true,
                x = 30, y = 30, w = WIDTH - 60, h = HEIGHT - 60,
                parent = window,
                textBody = infoText,
                style = {shape = {}, text = {font = "GillSans-Light"}},
                x = 20, y = 20, w = WIDTH * 0.5, h = HEIGHT * 0.5

    On creation of these I get this error twice, I'm assuming once for each element:

    Style:130: bad argument #1 to 'pairs' (table expected, got nil)
    stack traceback:
        [C]: in function 'pairs'
        Style:130: in field 'setStyle'
        TextScroll:60: in method 'drawContent'
        FRAME:215: in method 'draw'
        FRAME:239: in method 'draw'
        Soda:51: in field 'draw'
        Main:271: in function 'drawing'
        Main:248: in function 'draw'

    It works when I don't try to specify a custom font for the TextScroll, though.

    So that must be the problem, but the documentation for the 'style' parameter reads "coming soon", so I don't know what I'm doing wrong.

    @yojimbo2000 , three questions:
    1. Is TextScroll the best ui element to use to place text in a custom position inside a parent element, even if that text will never need to scroll?
    2. How do I change just the font of a TextScroll without it crashing?
    3. Darn it I forgot the third. Oh well. I'll just make one up. What a color are your socks?

  • Posts: 1,799

    @yojimbo2000 , here's my current code.

    function addInfoScreen()
        local infoText = [['Double Choose' is two small adventure games written entirely by my daughters Rosie and Charlotte.  Tap on Rosie to play her game, and tap on Charlotte to play hers. 
    Rosie did the art for her game, and I did most of Charlotte's game under her firm art-direction. 
    You'll enjoy the games most by trying to find all the possible endings.  Rosie's game has awesome emotionally-excruciating endings.  Charlotte actually included a little adventure-game-style inventory management--impressive for a five-year-old! 
    We made it with the excellent iPad app Codea.  We hope you enjoy our games, and we especially hope they inspire other kids to make games too.  Try Codea, it rocks!]]
        --define parameters for the info window
        local insetX, insetY = math.floor(WIDTH * 0.04), math.floor(HEIGHT * 0.04)
        local windowW, windowH = WIDTH - (insetX * 2), HEIGHT - (insetY * 2)
        local textW, textH = windowW - (insetX * 2), windowH - (insetY * 2)
        local iFontName = "GillSans-Light"
        local iFontSize = 1.75
        local infoColor = color(198, 110, 198, 255)
        local showInfo = function()
            local window = Soda.Window {
            title = "",
            blurred = true,
            close = true,
                style = {
                    shape = {fill = color(37, 37, 37, 255), stroke = "midGrey", strokeWidth = iStrokeWidth}, text = {}}, 
            x = insetX, y = insetY, w = windowW, h = windowH
            local subWindow = Soda.Window {
                parent = window,
                title = infoText,
                style = {
                    shape = {fill = color(0, 0, 0, 0), stroke = "midGrey", strokeWidth = iStrokeWidth}, 
                    text = {fontSize = iFontSize,  font = iFontName, fill=infoColor, textAlign = LEFT},
                x = 0, y = -1 * windowH / 3.65, w = windowW, h = windowH
        --determine the correct the size of the info circle
        local iCircleSize = WIDTH * 0.065
        --define the placement of the info circle
        local iCircleOffset = iCircleSize * 0.48
        local infoCircleFontSize = iFontSize * 1.9
        local iStrokeWidth = infoCircleFontSize * 0.85
        local iCircleColor = color(144, 125, 144, 255)
        infoButtonTable = Soda.Button{
            title = "i",
            style = {
                shape = {fill = color(0, 0, 0, 0), stroke = iCircleColor, strokeWidth = iStrokeWidth}, 
                text = {fontSize = infoCircleFontSize,  font = "GillSans", fill=iCircleColor},
                highlight = {
                    text = {fontSize = infoCircleFontSize,  font = "GillSans", fill=color(0, 0, 0, 0)},
                    shape = {fill = iCircleColor}
            shape = Soda.ellipse,
            x = 20, y = 20, w = iCircleSize, h = iCircleSize,
            callback = showInfo

    Of note:
    * I couldn't get text scroll and text window to change their font size, font, and font color, so I ended up using two window elements.
    * Because window elements only display text in the title area, to get the info text placed correctly I had to do kludgy things like 'y = -1 * windowH / 3.65', manually scooting the child element down so that the text appeared to be actually contained inside the parent window.
    * I had to use math.floor (...) on my x/y calculations to get my windows to appear at all; as I noted in the main Soda thread, x/y values that have decimals don't seem to work.

    Please let me know if you have any tips!

  • Posts: 2,020
    @UberGoober see my comment on the main Soda thread, so if you've made one frame the child of another, you can use relational coordinates, no need to do this `x = 0, y = -1 * windowH / 3.65, w = windowW, h = windowH`, you should be able to pin a frame to its parent with `x=0,y=0,w=1,h=1` (1 parsed as 100%)
  • Posts: 1,799

    @yojimbo2000 , those are two separate issues. The proportional concept is a neat idea, I reply to it in the other thread.

    But in this case, I have to do y = -1 * windowH / 3.65.

    The reason is that I want to display that big chunk of text in a custom font, size, and color.

    But at present I can't change the font or fontSize or font color of a TextWindow or a TextScroll.

    To get a custom font, what I'm actually using is the title value of a Window element. Then I put that element inside a parent Window.

    Of course, the title string tries to position itself near the top of its Window's bounds, so to make the text look centered inside its parent I have to slide the child window down.

    Through trial and error I came to the y = -1 * windowH / 3.65 as the value that looked the most vertically centered.

    I know this is super, super kludgey but without being able to style the text inTextWindows I couldn't figure out a better way.

  • Posts: 1,799
    @yojimbo2000 , what soda UI element would you recommend using as a label?
  • Posts: 2,020

    Use Soda.frame. All elements have a title property, use this to label the frame. Confusingly, the coordinates of the title are held in a property called label. It defaults to the centre-top of the frame, but you can override this.

  • Posts: 1,799

    @yojimbo2000, how does the override work?

  • Posts: 2,020
    Set the label. It has x and y coords, which work the same as other positions in soda. Eg 0.5, 0.5 to centre the label.
  • Posts: 1,799

    @yojimbo2000 :smile:


    Is there an element that displays images?

  • Posts: 1,799


    Have converted all of the app to Soda except for the images. Your library is awesome and improves the feel of the app a million percent.

    One odd bug I wonder if you can advise me on. For some reason I can't make blurry buttons: setting blurred to true crashes the game.

    I've made an importable version of the app here:, it replaces all custom images with default images from Codea.

    If you want to see the crash happen, import that project, make Soda a dependency, and under the tab "TwoChoiceAdventure" uncomment the text "blurred = true" at line 201.

  • Posts: 1,799

    @yojimbo2000 I'm entering a plea for an Image element in SODA.

    The SODA proportional-positioning system becomes so convenient that going back and forth between that and the Codea system starts to be a big hassle.

    Placing images is really the only reason I need to use the Codea system anymore. Please make a SODA Image element so my graphics routines can be all-singing, all-dancing, all-SODA all the time!

  • em2em2
    Posts: 194

    Shouldn't it be trivial to implement your own image frame element? You could then post it here and then maybe @yojimbo2000 can pull it into his main project when he has time.

  • AnatolyAnatoly Mod
    Posts: 893

    Does really everyone use Soda? Okay, once installed, how to move Soda to your project? Do you have to copy all files there or – ?

  • Posts: 1,799
    @TokOut you just use SODA as a dependency, you can see the menu for that when you press the "+" button for making a new tab inside a project.

    @em2 I looked into that and trivial it's not.

    Part of the problem comes from the fact that Codea separates 2D rendering and 3D rendering. SODA is actually all 3D meshes, so its drawing routines all happen during Codea's 3D rendering phase. To simply stick a normal Codea `sprite()` call in the middle of a SODA element would be sticking a 2D render in among the 3D rendering, and that has unpredictable results.

    Another part of the problem is that @yojimbo2000 has implemented a rather elegant parent-child relationship, wherein the child's positioning and size information are all interpreted relative to the origin and dimensions of the parent. This way, a button in the corner of a window stays in the same place relative to the window even when the user moves the window around the screen. This is all really great, but it is also fully incompatible with the `sprite()` coordinate system, which always references the absolute values of the current screen. It is technically possible to pull some wizardry to translate those sprite coordinates based on a parent's position, but the logistics of that--not mention trying to integrate it with the existing code--are beyond me.

    But take a look for yourself, if you want--perhaps an easy solution will occur to you. For me, it looks really really really non-trivial.
Sign In or Register to comment.