Soda v0.7: gorgeous and powerful GUI/ windowing/ button library. Now with fully selectable text.

@brookesi that’s an interesting idea with the callbacks, but you can do that anyway with closures, no?

eg method of a class instance:

callback = function(passSomeArgs) anInstance:aMethod(passSomeArgs, moreArgs) end

or, if no arguments and no class instance need to be passed it can just be

callback = table.withAFunction

Hi @yojimbo2000,

Ah, ok, thought there may be upvalue issues or something, but that makes sense, nice!

Brookesi

Yeah I didn’t realise just how powerful closures were until I was researching coroutines. Closures remember the upvalues, in this case the class instance.

I think I’ve been using them without realising it :wink:

In my UIManager I have a rectangle class that uses global offsets as static members of the rectangle class,this is so I can animate flying the UI in or out from different directions, but then I realized that two UIs would share this offset and interfere with each other so I declared my class and all its functions as a local in a closure and returned that, so I can get a different ‘version’ of the class specific to each UI instance…

All good fun…

Brookesi

@TimurEke the list panel in that screenshot is not set to be blurry, just translucent. Maybe it should just be solid colour. I’m not sure that the translucency looks that great on its own (without the blurriness).

What’s different with your text scrolling? It seems the same as mine, in terms of the algorithm for the inertia and the method of actually moving the text.

Mine adds support for bodies of text that are taller than the screen (text doesn’t display anything if what you’re texting exceeds either the width or the height of the screen), and elastic snap-back (which is currently buggy if the text body is shorter than than the text box)

@yojimbo2000 that’s a stunning UI library you’ve made. So pretty, great work.

@yojimbo2000, very well done! Looks beautiful and performs a lot better than i expected it would on my old iPad 2. And the demo is cool too: i wonder how people started by pressing the red button…

Beautiful work. Time to retire Cider… I’m going to use this myself!

function equations()
    
    var="FV"
    
    local panel = Soda.Control { 
        title = "Résolutions d'équations", hidden = true, x=50, y=160, w=900, h=500, 
        blurred = true, style = Soda.style.darkBlurred
    }
    
    local menu = Soda.MenuButton {x = -20, y = -20}
    menu.callback = function() panel:show(RIGHT) menu:hide(RIGHT) end 
    
    Soda.BackButton {
        parent = panel, direction = RIGHT, x = -20, y = -20,
        callback = function() panel:hide(RIGHT) menu:show(RIGHT) end
    }

    local panel1 = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local panel2 = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local panel3 = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local panel4 = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local panel5 = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local panel6 = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    Soda.Segment{
        parent = panel, x = 20, y = -80, w = -20, h = 40,
        text = {"TVM","Cash Flow","Bond","Dépréciation","Statistique","Eq2nd"},
        panels = { panel1, panel2, panel3, panel4, panel5, panel6
        }
    }
   
    Soda.TextEntry { parent=panel1, x=10, y=-30, w=400, h=40, title = "N = Nombre de paiements =  ", default = "0"}
    Soda.TextEntry { parent=panel1, x=10, y=-80, w=400, h=40, title = "I/YR = Intérêt / an = ", default = "0"}
    Soda.TextEntry { parent=panel1, x=10, y=-130, w=400, h=40, title = "PV = Present Value = ", default = "0"}
    Soda.TextEntry { parent=panel1, x=10, y=-180, w=400, h=40, title = "PMT = Paiement = ", default = "0"}
    Soda.TextEntry { parent=panel1, x=10, y=-230, w=400, h=40, title = "FV = Future Value = ", default = "0"}
    Soda.TextEntry { parent=panel1, x=10, y=-280, w=400, h=40, title = "P/YR = Nb Paiements / an = ", default = "12"}
    Soda.Switch{ parent=panel1, x = 430, y = -280, title = "Début / Fin" }
    
    Soda.TextEntry { parent=panel2, x=10, y=-50, w=280, h=40, title = "CF0 = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=10, y=-100, w=280, h=40, title = "I = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=10, y=-150, w=280, h=40, title = "NPV = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=10, y=-200, w=280, h=40, title = "NFV = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=10, y=-250, w=280, h=40, title = "PB = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=410, y=-50, w=280, h=40, title = "DPB = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=410, y=-100, w=280, h=40, title = "IRR = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=410, y=-150, w=280, h=40, title = "RI = ", default = "0"}
    Soda.TextEntry { parent=panel2, x=410, y=-200, w=280, h=40, title = "MOD = ", default = "0"}
    
    Soda.TextEntry { parent=panel3, x=10, y=-50, w=280, h=40, title = "SDT = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=10, y=-100, w=280, h=40, title = "CPN = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=10, y=-150, w=280, h=40, title = "RDT = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=10, y=-200, w=280, h=40, title = "RV = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=10, y=-250, w=280, h=40, title = "ACT = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=410, y=-50, w=280, h=40, title = "YLD = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=410, y=-100, w=280, h=40, title = "PRI = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=410, y=-150, w=280, h=40, title = "AI = ", default = "0"}
    Soda.TextEntry { parent=panel3, x=410, y=-200, w=280, h=40, title = "DUR = ", default = "0"}

    Soda.TextEntry { parent=panel4, x=10, y=-50, w=260, h=40, title = "SL = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=10, y=-100, w=260, h=40, title = "SYD = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=10, y=-150, w=260, h=40, title = "DB = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=10, y=-200, w=260, h=40, title = "DBX = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=10, y=-250, w=260, h=40, title = "SLF = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=300, y=-50, w=260, h=40, title = "DBF = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=300, y=-100, w=260, h=40, title = "LIF = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=300, y=-150, w=260, h=40, title = "MO1 = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=300, y=-200, w=260, h=40, title = "DT1 = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=300, y=-250, w=260, h=40, title = "CST = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=590, y=-50, w=260, h=40, title = "SAL = ", default = "0"}
   Soda.TextEntry { parent=panel4, x=590, y=-100, w=260, h=40, title = "YR = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=590, y=-150, w=260, h=40, title = "DEP = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=590, y=-200, w=260, h=40, title = "RBV = ", default = "0"}
    Soda.TextEntry { parent=panel4, x=590, y=-250, w=260, h=40, title = "RDV = ", default = "0"}
    
    Soda.TextEntry { parent=panel5, x=10, y=-50, w=280, h=40, title = "X = ", default = "{  }"}
    Soda.TextEntry { parent=panel5, x=10, y=-100, w=280, h=40, title = "Y = ", default = "{  }"}
    
    Soda.TextEntry { parent=panel6, x=10, y=-50, w=280, h=40, title = "a = ", default = "0"}
    Soda.TextEntry { parent=panel6, x=10, y=-100, w=280, h=40, title = "b = ", default = "0"}
    Soda.TextEntry { parent=panel6, x=10, y=-150, w=280, h=40, title = "c = ", default = "0"}

    Soda.Button{
    parent = panel1, title = "Calcul", style = Soda.style.warning, 
    x = -20, y = 20, w = 200, h = 40, 
    callback = 
        function()
            if var=="PMT" then end
            Soda.Alert1{ 
                title = var.." = ", y=0.6, 
                style = Soda.style.darkBlurred, blurred = true, 
                alert = true
            }
        end
    }   
    
    local countyName = Soda.TextEntry{
        parent = panel1, x = 430, y = -30, w = 380, h = 40,
        shapeArgs = {corners = 1 | 2},
        title = "Calculer :", default = "FV", inactive = true
    }
    
    local counties = Soda.List{
        parent = panel1, hidden = true, x = 430, y = -70, w = 420, h = 200,
        text = {"N","I/YR","PV","PMT","FV","P/YR"}
    }
    
    counties.callback = function(txt) countyName:inputString(txt) var=txt counties:hide() end
    
    Soda.DropdownButton{
        parent = panel1, style = Soda.style.default, x = -10, y = -30,
        shapeArgs = {corners = 4 | 8},
        callback = function() counties:toggle() end
    }
    
end

hello,

i manage to extract information in soda.list

counties.callback = function(txt) countyName:inputString(txt) var=txt counties:hide() end

but how extract tha value in soda.textentry

i tried the callback function in soda.textentry but it doesn’t work

can you help me please

@hpsoft thanks for trying Soda and for posting your code. I haven’t had a chance to run your code yet, but I will do tomorrow. TextEntry currently has an output method TextEntry:output() which returns the value in the textbox. I can see you have a lot of text entry fields so perhaps this method isn’t convenient for you. I could implement a callback for TextEntry if that would be useful (it would be consistent with the interface for lists). Should the callback trigger on each key press, or just when the user hits return/ closes the keyboard? Which would be most useful do you think?

(this is so impressive)

if i replace code by

Soda.TextEntry { parent=panel1, x=10, y=-30, w=400, h=40, title = "N = Nombre de paiements =  ", default = "0", callback = function()   N=TextEntry:output()   end }

N is empty, i don’t understand

@hpsoft TextEntry doesn’t have a callback (yet). I’m going to add it. I’ve decided that the most convenient way to implement this is if the callback is triggered when the user exits the textbox, either by pressing return, pressing hide keyboard, or selecting another button (which hides the keyboard). I’ll put the updated code on GitHub in the next day or so.

great thank you
I will end my example…

and i will add 2 horizontal menus
and try to add sound effects ( like laser ) when panel appear or desappear
perhaps with waveform

function equations2()
    
    var="FV"
    
    local panel = Soda.Control { 
        title = "Calculus", hidden = true, x=50, y=50, w=900, h=700, 
        blurred = true, style = Soda.style.darkBlurred
    }
    
    local menu = Soda.MenuButton {x = -20, y = -20}
    menu.callback = function() panel:show(RIGHT) menu:hide(RIGHT) end 
    
    Soda.BackButton {
        parent = panel, direction = RIGHT, x = -20, y = -20,
        callback = function() panel:hide(RIGHT) menu:show(RIGHT) end
    }
  
    local finpanel = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local mathpanel = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local statpanel = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local physpanel = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local otherpanel = Soda.Frame{
        parent = panel, hidden = true, x = 20, y = 20, w = -20, h = -140,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    Soda.Segment{
        parent = panel, x = 20, y = -80, w = -20, h = 40,
        text = {"Finance","Math","Stat Proba","Chemical Physics","Other"},
        panels = { finpanel, mathpanel , statpanel, physpanel, otherpanel}
    }
    
    local tvmpanel = Soda.Frame{
        parent = finpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local cfpanel = Soda.Frame{
        parent = finpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local bondpanel = Soda.Frame{
        parent = finpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local deprecpanel = Soda.Frame{
        parent = finpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }

    Soda.Segment{
        parent = finpanel, x = 20, y = -10, w = -20, h = 40,
        text = {"TVM","Cash Flow","Bond","Depreciation"},
        panels = { tvmpanel, cfpanel, bondpanel, deprecpanel
        }
    }
    
    local solverpanel = Soda.Frame{
        parent = mathpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local eq2ndpanel = Soda.Frame{
        parent = mathpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }

    local eq3ndpanel = Soda.Frame{
        parent = mathpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }

    local convertpanel = Soda.Frame{
        parent = mathpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local systempanel = Soda.Frame{
        parent = mathpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    local graphpanel = Soda.Frame{
        parent = mathpanel, hidden = true, x = 20, y = 20, w = -20, h = -80,
        shape = Soda.RoundedRectangle, style = Soda.style.translucent,
    }
    
    Soda.Segment{
        parent = mathpanel, x = 20, y = -10, w = -20, h = 40,
        text = {"Solver","Eq2nd","Eq3nd","Convert","System","Graph"},
        panels = { solverpanel, eq2ndpanel, eq3ndpanel, convertpanel, systempanel , graphpanel
        }
    }
        
    Soda.TextEntry { parent=tvmpanel, x=10, y=-30, w=0.5, h=40, title = "N =  ", default = "0"}
    Soda.TextEntry { parent=tvmpanel, x=10, y=-80, w=0.5, h=40, title = "I/YR = ", default = "0"}
    Soda.TextEntry { parent=tvmpanel, x=10, y=-130, w=0.5, h=40, title = "PV = ", default = "0"}
    Soda.TextEntry { parent=tvmpanel, x=10, y=-180, w=0.5, h=40, title = "PMT = ", default = "0"}
    Soda.TextEntry { parent=tvmpanel, x=10, y=-230, w=0.5, h=40, title = "FV = ", default = "0"}
    Soda.TextEntry { parent=tvmpanel, x=10, y=-280, w=0.5, h=40, title = "P/YR = ", default = "12"}
    Soda.Switch{ parent=tvmpanel, x = 10, y = -330, title = "Début / Fin" }
    
    Soda.Button{
    parent = tvmpanel, title = "Compute", style = Soda.style.warning, 
    x = -100, y = 20, w = 200, h = 40, 
    callback = 
        function()
            if var=="PMT" then end
            Soda.Alert1{ 
                title = var.." = ", y=0.6, 
                style = Soda.style.darkBlurred, blurred = true, 
                alert = true
            }
         end
    }
    
    local tvmVar = Soda.TextEntry{
        parent = tvmpanel, x = 430, y = -30, w = 340, h = 40, shapeArgs = {corners = 1 | 2},
        title = "Compute : ", default = "FV", inactive = true
    }
    
    local tvm = Soda.List{
        parent = tvmpanel, hidden = true, x = 430, y = -70, w = 380, h = 240,
        text = {"N","I/YR","PV","PMT","FV","P/YR"}
    }
    
    tvm.callback = function(txt) tvmVar:inputString(txt) var=txt tvm:hide() end
    
    Soda.DropdownButton{
        parent = tvmpanel, style = Soda.style.default, x = -10, y = -30,
        shapeArgs = {corners = 4 | 8}, callback = function() tvm:toggle() end
    }
    
Soda.TextEntry { parent=cfpanel, x=10, y=-30, w=0.5, h=40, title = "CF0 = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=10, y=-80, w=0.5, h=40, title = "I = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=10, y=-130, w=0.5, h=40, title = "NPV = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=10, y=-180, w=0.5, h=40, title = "NFV = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=10, y=-230, w=0.5, h=40, title = "PB = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=10, y=-280, w=0.5, h=40, title = "DPB = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=10, y=-330, w=0.5, h=40, title = "IRR = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=10, y=-380, w=0.5, h=40, title = "RI = ", default = "0"}
    Soda.TextEntry { parent=cfpanel, x=430, y=-30, w=380, h=40, title = "MOD = ", default = "0"}
    
    Soda.TextEntry { parent=bondpanel, x=10, y=-30, w=0.5, h=40, title = "SDT = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=10, y=-80, w=0.5, h=40, title = "CPN = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=10, y=-130, w=0.5, h=40, title = "RDT = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=10, y=-180, w=0.5, h=40, title = "RV = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=10, y=-230, w=0.5, h=40, title = "ACT = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=10, y=-280, w=0.5, h=40, title = "YLD = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=10, y=-330, w=0.5, h=40, title = "PRI = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=10, y=-380, w=0.5, h=40, title = "AI = ", default = "0"}
    Soda.TextEntry { parent=bondpanel, x=430, y=-30, w=380, h=40, title = "DUR = ", default = "0"}

    Soda.TextEntry { parent=deprecpanel, x=10, y=-30, w=0.5, h=40, title = "SL = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=10, y=-80, w=0.5, h=40, title = "SYD = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=10, y=-130, w=0.5, h=40, title = "DB = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=10, y=-180, w=0.5, h=40, title = "DBX = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=10, y=-230, w=0.5, h=40, title = "SLF = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=10, y=-280, w=0.5, h=40, title = "DBF = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=10, y=-330, w=0.5, h=40, title = "LIF = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=10, y=-380, w=0.5, h=40, title = "MO1 = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=430, y=-30, w=380, h=40, title = "DT1 = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=430, y=-80, w=380, h=40, title = "CST = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=430, y=-130, w=380, h=40, title = "SAL = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=430, y=-180, w=380, h=40, title = "YR = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=430, y=-230, w=380, h=40, title = "DEP = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=430, y=-280, w=380, h=40, title = "RBV = ", default = "0"}
    Soda.TextEntry { parent=deprecpanel, x=430, y=-330, w=380, h=40, title = "RDV = ", default = "0"}
    
    Soda.TextEntry { parent=solverpanel, x=10, y=-30, w=-10, h=40, title = "Equation = "}
    
    Soda.Button{
    parent = solverpanel, title = "Compute", style = Soda.style.warning, 
    x = -100, y = 20, w = 200, h = 40, 
    callback = 
        function()
            Soda.Alert1{ 
                title = var.." = ", y=0.6, 
                style = Soda.style.darkBlurred, blurred = true, 
                alert = true
            }
        end
    }
    
    local solverVar = Soda.TextEntry{
        parent = solverpanel, x = 430, y = -80, w = 340, h = 40, shapeArgs = {corners = 1 | 2},
        title = "Algo : ", default = "Dichotomy", inactive = true
    }
    
    local solver = Soda.List{
        parent = solverpanel, hidden = true, x = 430, y = -120, w = 380, h = 240,
        text = {"Dichotomy","Newton-Raphson","Intersecting","Regula Falsi","Müller Method","IQI","Brent Method","Conjugate Gradient","Fixed Point Method","Sturm Theorem"}
    }
    
    solver.callback = function(txt) solverVar:inputString(txt) var=txt solver:hide() end
    
    Soda.DropdownButton{
        parent = solverpanel, style = Soda.style.default, x = -10, y = -80,
        shapeArgs = {corners = 4 | 8}, callback = function() solver:toggle() end
    }
    
    Soda.TextEntry { parent=eq2ndpanel, x=10, y=-30, w=150, h=40, title = "a^2+b^2+c=0"}
    Soda.TextEntry { parent=eq2ndpanel, x=10, y=-80, w=0.5, h=40, title = "a = ", default = "0"}
    Soda.TextEntry { parent=eq2ndpanel, x=10, y=-130, w=0.5, h=40, title = "b = ", default = "0"}
    Soda.TextEntry { parent=eq2ndpanel, x=10, y=-180, w=0.5, h=40, title = "c = ", default = "0"}
    
    Soda.TextEntry { parent=eq3ndpanel, x=10, y=-30, w=200, h=40, title = "a^2+b^2+c^2+d=0"}
    Soda.TextEntry { parent=eq3ndpanel, x=10, y=-80, w=0.5, h=40, title = "a = ", default = "0"}
    Soda.TextEntry { parent=eq3ndpanel, x=10, y=-130, w=0.5, h=40, title = "b = ", default = "0"}
    Soda.TextEntry { parent=eq3ndpanel, x=10, y=-180, w=0.5, h=40, title = "c = ", default = "0"}
    Soda.TextEntry { parent=eq3ndpanel, x=10, y=-230, w=0.5, h=40, title = "d = ", default = "0"}
    
    Soda.TextEntry { parent=convertpanel, x=10, y=-30, w=-10, h=40, title = "Value = "}
    
    Soda.Button{
    parent = convertpanel, title = "Convert", style = Soda.style.warning, 
    x = -100, y = 20, w = 200, h = 40, 
    callback = 
        function()
            Soda.Alert1{ 
                title = var.." = ", y=0.6, 
                style = Soda.style.darkBlurred, blurred = true, 
                alert = true
            }
        end
    }
    
    local convertVar = Soda.TextEntry{
        parent = convertpanel, x = 430, y = -80, w = 340, h = 40, shapeArgs = {corners = 1 | 2},
        title = "Conversion : ", default = "Base", inactive = true
    }
    
    local convert = Soda.List{
        parent = convertpanel, hidden = true, x = 430, y = -120, w = 380, h = 160,
        text = {"Base","Morse","Roman","Unit"}
    }
    
    solver.callback = function(txt) convertVar:inputString(txt) var=txt convert:hide() end
    
    Soda.DropdownButton{
        parent = convertpanel, style = Soda.style.default, x = -10, y = -80,
        shapeArgs = {corners = 4 | 8}, callback = function() convert:toggle() end
    }
    
    Soda.TextEntry { parent=systempanel, x=10, y=-30, w=0.5, h=40, title = "Numbers of unknowns = ", default = "0"}
    
    Soda.TextEntry { parent=graphpanel, x=10, y=-30, w=800, h=40, title = "f(x) = "}
    Soda.TextEntry { parent=graphpanel, x=10, y=-80, w=0.5, h=40, title = "Xmin = "}
    Soda.TextEntry { parent=graphpanel, x=10, y=-130, w=0.5, h=40, title = "Xmax = "}
    Soda.TextEntry { parent=graphpanel, x=10, y=-180, w=0.5, h=40, title = "Xstep = "}
    Soda.TextEntry { parent=graphpanel, x=430, y=-80, w=380, h=40, title = "Ymin = "}
    Soda.TextEntry { parent=graphpanel, x=430, y=-130, w=380, h=40, title = "Ymax = "}
    Soda.TextEntry { parent=graphpanel, x=430, y=-180, w=380, h=40, title = "Ystep= "}
    
    Soda.TextEntry { parent=statpanel, x=10, y=-30, w=-10, h=40, title = "X = ", default = "{  }"}
    Soda.TextEntry { parent=statpanel, x=10, y=-80, w=-10, h=40, title = "Y = ", default = "{  }"}
    
    Soda.TextEntry { parent=physpanel, x=10, y=-30, w=-10, h=40, title = "Balance Equation = "}
    
end

here is the second version of example ( in 2 parts , sorry for the long text )
it s very fantastic !!! simultaneus menubars works perfectly and very fast.
I have a small problem ( i had to replace w=0.5 or w=1 by w=380 and w=800 )
if not exceeded the fields of the panel. It s a very good work ^:)^

@yojimbo2000 my second most anboying problem that i do not manage to solve ( excuse my poor english )

my first dropdown button ( in tvm pannel works perfectly )
but the other dropdown button ( in solver panel and convertpanel ) does’nt work
perhaps is there an order i’ve missed or a problem with text variable

Thanks

@hpsoft that’s quite an impressive interface you’ve built! There’s one error in your code producing the drop down bug (but also one error in my code). On line 256, you define the convert callback with solver, overwriting the previous solver callback. Change the start of the line to convert.callback = .

However, this also brought to light a bug in Soda code. If you activate the convert and solver drop downs, but then switch back to the first dropdown, you’ll notice that the image of the second menu is displayed in place of the first one. This is a bug to do with how roundedRect caches shapes. Because two of the menus are the same dimensions, roundedRect caches them as a single mesh (what it’s supposed to do), but then doesn’t switch the textures when you switch between them. I’ll have a fix for this bug, and quite a few new features later today. Thank you for bringing this bug to light!