Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » GOOEY QUESTION : HBox, VBox, FlowLayout oh my!

Credits go to amarillion, Arthur Kalliokoski, bamccaig, Elias, frank.n, and jmasterx for helping out!
This thread is locked; no one can reply to it. rss feed Print
GOOEY QUESTION : HBox, VBox, FlowLayout oh my!
Edgar Reynaldo
Major Reynaldo
May 2007
avatar

https://www.allegro.cc/forums/thread/608404/932405#target

How should flow layouts work? I just implemented one in Eagle, that lays out widgets according to rows or columns first and by columns or rows second according to a widget's preferred size. Right now I set each widget to expand as much as possible once the row height is determined so it is completely taken up. This serves as a stackable hbox. I also made it possible to swap the major and minor axes of the flow so you can do vertical flows. Then I made it possible to anchor the flow at any corner of the widget's inner area.

Let's discuss GUIs here shall we? There are a million of them out there by now. I'm just hoping I can save some noobs some time with the writing of my library.

Should I have a separate hbox and vbox? It would be simple to subclass them and override a function maybe.

Also, handy tip of the day :
Look up Jump Tables and learn the power of a vtable. The cool thing about C++ is that you don't have to manually write vtables anymore.

8-)

amarillion
Member #940
January 2001
avatar

Perhaps it should work like Flexbox?

jmasterx
Member #11,410
October 2009

The flow layout in agui is really simple,
It will layout the widgets from left to right and the tallest on that row is the starting point for the next row, but I added a few sugar things in there to sweeten it if you wanna look. https://github.com/jmasterx/Agui/blob/master/src/Agui/FlowLayout.cpp

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Flex box is super extensible sure, but I want to keep this simple.

I can add alignment to each widget easily with the existing flow layout.

I also have a simple table layout and many more. Honestly, the last thing I ever needed was a FlowLayout. I think it's kind of the lazy programmer's way out of his little box in the basement.

Elias
Member #358
May 2000

A flow layout can be useful if you don't know the size at all, for example you have a picture gallery and then on a phone screen held upright there would be one item per row while on a desktop screen it would be 10 items per row.
I used one just recently, without you'd have to add some manual code to determine the number of columns based on sizes (which you may or may not know though) so it can get very complicated. Flow layout on the other hand is really simple, from that perspective :)

--
"Either help out or stop whining" - Evert

bamccaig
Member #7,536
July 2006
avatar

Ideally the designer of a graphical interface should not have to specify sizes at all. Any hard-coded sizes will require the app to be maintained as displays and devices change. If you describe the ideas instead of how to do them then the GUI engine can build itself from the instructions. In a perfect world, the system should make it work optimally with whatever space is available. That is complicated to do, which is all the more reason to get it right in the GUI framework instead of every app having to reinvent the wheel and doing poorly at it with limited access to the guts.

For a simple example, a login dialog. It has 3 labels and 3 fields (username, password, and remember_me), and 3 buttons (login, cancel, forgot_password). I would want this to use the right amount of space automatically (when it's not maximized, if it supports that). I shouldn't even have to think about how many pixels to display everything in. That depends on the GUI itself anyway. The GUI should be able to generate the dialog by calculating the minimum space, and then factoring in some widget-specific rules to ensure no widgets become broken or unusable. I'd want to just pass the GUI a hierarchy like this and it can figure out the rest:

  1. window

    1. flowbox(vertical_first)

      1. flowbox(horizontal_first)

        1. label "Username:"

        2. textbox "username"

      2. flowbox(horizontal_first)

        1. label "Password:"

        2. textbox "password"

      3. flowbox(horizontal_first)

        1. label "Remember Me"

      4. flowbox(horizontal_first)

        1. button "Cancel"

        2. button "Forgot Password"

        3. button "Login"

That should be enough information to generate a user interface. And it should be possible for the interface to automatically resize itself and recalculate all of the widget sizes on the fly. If the user makes the window bigger than it needs to be then widgets can be spaced apart until some threshold is reached, and then just centre the contents in the centre/middle IMO as if a tiny dialog was floating inside. Whether you can do these calculations on the fly reasonably fast for a complicated GUI would remain to be seen I guess. But that's my ideal.

I did a very basic tutorial in Qt a while back, and that's what I loved about it. It had layouts that I was able to just drop things into, and didn't have to worry about sizing or layout. It was all automatic.

I'm sure it's way more complicated than it looks though. That other thread goes into some of the details.

frank.n
Member #16,879
July 2018

For lgui, I thought quite a lot about layouts. It's a bit difficult to get right because layout needs to adapt both top-down and bottom-up.
If the window size (the top widget) changes, widgets that depend on their parent's size need to be resized, potentially affecting every widget down to the leaves of the widget tree.
On the other hand, if e.g. a text changes such that a button or a label needs more space, it potentially affects every widget up to the top (or root) of the widget tree.
Because layout works in two ways like this, I found it's mandatory to have a two-pass layout process: the first pass is to measure (potentially) every widget top-down and returning and aggregating sizes back bottom-up. Only then can layout be executed in a second pass. If you try to do everything in one pass (i.e. adapting the parent's size when a child is added), there will be edge cases that are impossible to get right.
Then there are nasty special cases like scrollable areas which may provide unlimited space in one dimension, but not the other. So changes within a scrollable area might affect the surroundings, but it's not compulsory. And of course they have scroll bars which might (dis)appear, affecting the other dimension when the size of one dimension is changed. Also, there are things like word-wrapped text which can behave in nasty ways.

What I wanted in lgui is to have layout classes independent of the widgets (like Qt does). So there is a BasicContainer widget (and subclasses) which you can set layouts on, but the layout classes are a different hierarchy. You can also nest layouts without needing a widget container for each sub-layout. I'm not so sure whether this has been a good decision, since the code syncing the children of layouts and widgets is a bit difficult to understand. From a class design perspective, I still prefer this approach.

When I added basic animation (and transformation) support, I've also experimented with animating the layout changes 8-), however, I'd still consider this experimental. There should be a test for that in the demo.

Soooo what I wanted to say is that IMHO the layout system itself needs to be quite robust.
Until now, I found lgui's VBoxLayout, HBoxLayout, RelativeLayout, SimpleTableLayout and FlowLayout sufficient. The FlowLayout just stacks widgets from top-to-bottom, left-to-right per default, also providing the options to solely operate vertically and horizontally. So, in a way, it's a more of a bottom-up kind of layout (the children determine the size), whereas H/VBoxLayout are (potentially) also top-down kind of layouts if configured with stretch factors. There's also a SortedFlowLayout providing the possibility to sort the children which arose from a special use case I had.
These are all quite simple layouts as my layout needs were fulfilled and I finally wanted to move on to other topics. >:(

One thing with lgui's layout is that you need to pass an initial size for the top container (window). Of course you can query a minimum size hint for that, but you need to set it so that it is clear what space is considered available.

Another thing is that alignment provides a way to customize the usage of space assigned by the layout, so you have a widget within an invisible box in a way where it can be aligned right, centered or be stretched (interesting if layout operates in a top-down kind of way). Also, it serves the additional purpose to make it possible for the widget to greedily claim all space the layout offers.

bamccaig said:

If the user makes the window bigger than it needs to be then widgets can be spaced apart until some threshold is reached, and then just centre the contents in the centre/middle IMO as if a tiny dialog was floating inside. Whether you can do these calculations on the fly reasonably fast for a complicated GUI would remain to be seen I guess. But that's my ideal.

Well, basically, the GUI needs some way to know where to distribute space. E.g. shall remaining space go between the buttons or shall the buttons grow to fit.
It's probably a case of providing sensible default behaviors. E.g. in lgui, if the button is asked how wide it wants to be given an available width, it restricts itself to the width actually needed (IIRC). If you want different behavior, you may be able to force it with an alignment setting (or using a different layout).

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

So far, a variety of CSS3's flexbox as suggested by amarillion seems pretty nice. I like the justification options.

frank n - I see what you mean with a 2 pass layout system. That's not really a problem for me to do though.

Mostly I just use my RelativeLayout and my SimpleTable layouts and those cover about 95% of use cases.

But I like the idea of flexbox. Might get me back into web dev. :o :D

APPEND
So I'm still thinking through exactly how I want to implement the hbox and vbox. A CSS Flexbox has space around and space even options, and there is also the option of expanding contents to fit the box that I'm programming into my layout.

I implemented a simple version of preferred width and height, but for many widgets it doesn't make sense because there is no single optimal size for every kind of widget. There are reasonable things like an absolute minimum width and height for some widgets, but mostly you have to set a preferred size if you want a container like an hbox to work correctly unless you always set it to expand its contents as far as possible.

So what do I do if a widget doesn't have a preferred size? Text widgets and related composite widgets will obviously have an optimal (preferred?) size that makes the text completely visible, but what about things like sliders, scroll areas, and other hard to determine size type widgets?

TL:DR;
Spending too much time thinking about the features I want and not enough time programming.

Arthur Kalliokoski
Second in Command
February 2005
avatar

Spending too much time thinking about the features I want and not enough time programming.

I don't do enough of that. I would do much better to hold off coding until I grok in fullness. That doesn't mean you can't do some exploratory coding to test an idea, it just means you're not trying to produce the finished version by starting with "main.c" like so many wannebe Quake clone makers.

They all watch too much MSNBC... they get ideas.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I will literally spend days thinking about how to approach a problem and about 2 hours to code it. Then a few days or more to test and debug it.

EDIT
Just finishing up the box layouts, will write a demo to test them and share soon. Bump.

bamccaig
Member #7,536
July 2006
avatar

Go to: