Best way to layout complex GUIs


#1


I wonder if anyone can point me to sort of the "state of the art" for building a complex GUI with JUCE?

I've run into several ways of laying out JUCE components, but I'm not sure if there's a "best practice" or "most modern" way of doing it. For a simple GUI, any method would work, but for one with a lot of components that will likely grow and change in the future, I want a flexible and powerful method. Here are the options I've found so far:

* The JuceDemo app Widgets demo, particularly the ButtonsPage, uses straightforward setBounds calls on components. This is easy enough to understand, but not maintainable as a GUI evolves.

* The JuceDemo LookAndFeel demo uses a lot of removeFromLeft() and reduced() calls on Rectangle objects. Maybe a little better, but still close to hard-coded.

* The Introjucer has a GUI builder, but it's missing a lot of things. Many components can't be added directly, there's no built-in way to align multiple components together, I really wish I could group components, etc. There are alignment and anchoring options in the x/y/width/height values for components, but they're cumbersome to use - I wish I could alt-click or something to make one component align with another. Instead, you have to choose from a popup menu which can get difficult to navigate when you have a lot of components.

* The Component::setBounds method that takes a String expression is very cool, and I'm using it in some places, but I'd rather not have to organize this for every individual text label, checkbox, and button that I need in a GUI.


What I'd love is something like a way to express a GUI via JSON, including grid layouts, row and column layouts, etc., then load that GUI description into a window and show it. This system would also be sensitive to string length, so for example, if a label string was changed from "Width" to "Maximum image width", the label would expand, as well as shift other elements in the layout to make room for the new string. Maybe it wouldn't need to do a new layout at runtime, but at least the next time the JSON was loaded/parsed.

I've seen some posts here about layout managers, but they seemed like individual efforts that were maybe rather old and not maintained. Is there anything like this out there that I should evaluate?

Or is there some other approach I should take?

Below is an example screenshot. This is taken from the Photoshop preferences dialog. Suppose this was in JUCE, and under the Ray Tracer options I wanted to add another checkbox, "Indirect Illumination". A layout system would make this easy, but direct calls to setBounds or even using the Introjucer GUI tool would be painful. I'd have to set the location and size of the checkbox, then resize the "Interactive Rendering" group box, then resize the "Available VRAM" box to match, then shift around other boxes to make everything fit, etc. I think this example shows why one might want a layout system instead of positioning components one-by-one.


#2

We have a lot of ideas about new layout systems we can implement! Current favourite is to create some layout classes based on Flexbox. Probably won't have time to publish anything before our V4 launch, but it'll be a priority for us as soon as we can..


#3

I would love to see that happens :)

StretchableLayoutManager is ok, but you hit its limit very quickly.

 

I suppose the usage would be similar ?

 


#4

I have made a class, that simple layouts the child-elements of a component, like the way on a html page (with automatic wrap)  You can simple add (css-like) properties, to the components (like border top/left/right/bottom, size, stretch-factor etc.,aligning, or define properties as inherited ) which are stored in the property container of the class. Its very specific to my software, so i can't post it here. But something like this works wonderful.

 


#5

It'd be used in a vaguely similar way, but much more readable! We'll also be able to use C++11 to make it easier to write too.


#6

I've got a horribly custom setup that is a mix of this and more straightforward direct JUCE calls: 


        {
            UiDefinition panel (d, "METER", "stereo_savage_display", 430, 10, 200, 118);
            {
                UiDefinition gonio (panel.children, "Goniometer", "goniometer", "15, 35, 127, y+70");
                gonio.set("source", "output", nullptr);
            }
            {
                UiDefinition meter (panel.children, "Input", "flex_meter_multichannel",
                                    "135, 30, x+25, parent.height - 10");
                meter.set("stream", "input");
            }
            {
                UiDefinition meter (panel.children, "Output", "flex_meter_multichannel",
                                    "165, 30, x+25, parent.height - 10");
                meter.set("stream", "output");
            }

        }

And then debug builds have a GUI editor built into them so I can drag the components around and copy and paste the location values back into the stuff above.  

(I note that Edit and Continue looks like it's working in visual studio 2015 properly now which is nice for tweaking GUIs...)

 


#7

To answer myself…

Hey Mike, check out your new layout system here: