Introduction

Would it not be great configuring and switching dynamically, the layout of an application, as it were a property like a Color or a Font? Is there any layout manager that can do it?

By layout, we mean arranging and resizing the GUI components in a dialog. This can be done manually (e.g. using an editor), or automatically by a software piece called a layout manager. In both cases, laying out has always been something difficult to configure, change, and in most cases, impossible to be switched dynamically. Difficult until now, of course! In this article, we will see how easy it is to layout with EvaLayout.

Note that the flexibility and configuration of layouts, as it will be described, plays not only an important role in the look of the application, but also when modifying it, coding variants, and in the implementation of generic and rich components.

Background

There are lots of layout managers, and also quite a different number of approaches. EvaLayout belongs to the group of grid layouts, like GridBag layout (Java, Swing), Grig layout (Java, Eclipse, SWT), and specially TableLayout by Daniel Barbalace, and for C++ in Windows, the layout manager of Erwin Tratar and the one that I found very original from Marc Richarme.

The concepts of columns, rows, filling space, spanning columns and rows etc., are the same in all grid layouts. What is new in EvaLayout is the easy, clear, and flexible way of representing the whole layout information in a single text and, not less important, the decoupling between layout information and physical components that makes possible the advantages mentioned in the introduction.

Layout Info and Text Format in EvaLayout

Let us see the rules for defining an EvaLayout.

EvaLayout places all components within the cells of a grid - or table - of n columns and m rows. For the whole grid, the following can be defined:

A symmetric (same for left and right) horizontal margin

A symmetric (same for top and bottom) vertical margin

A horizontal gap (space between two adjacent columns)

A vertical gap (space between two adjacent rows)

For columns and rows, a header for each one determines its behaviour. There are three possibilities for these headers:

A (default): The size of the column/row will be adapted to the minimum required by the components in this column/row. That means, the maximum of the default sizes.

X: For expandable column/row. All expandable columns/rows will share the remaining space equally.

Number: Representing the width/height in pixels that the column/row has to have.

And finally, each cell in the grid may contain one of the following things:

blank, nothing is specified.

a name, it represents a logical name of a component, the cell where this name appears is the upper-left cell of the component.

sign -, a component that wants to occupy more cells at its right side (spanning columns) has to use this symbol in those cells.

sign +, a component that wants to occupy more cells at lower rows (spanning rows) has to use this symbol in that cells.

All this is given to the layout manager object (EvaLayoutManager) in a single text where the information is separated by commas. In the first line, the general margins and gaps are given, and the rest is for specifying the grid or the table. Note that the white spaces or blanks are only to make it more readable, they are actually not needed by EvaLayoutManager. Let us see an example. The text:

Now, we will see how to implement it in a C++ Windows application. We will show how to do it using the Windows API as it is done in the demo project, but it is also possible to do it in a MFC application and there is a how-to text that explains it.

Using the Code

For the implementation, we will need the following objects (note that except EvaLayoutInfo, the rest could be local objects):

Preparing or Loading the Layout Info

The preparation can be done, for instance, in the message WM_INITDIALOG, and consists in setting at least an Eva object or, in order to load more layouts, an EvaUnit object that can be used as if it were an array of Evas. This preparation can be done in two ways:

Setting the Layout Info into the Manager

This is just a call to the method setLayout of the layout manager. The message WM_INITDIALOG is a good place for that too, but note that this can also be performed wherever and whenever, to dynamically change the layout. After doing that, you should force a repaint, or better, a resize message. In the demo project, it is done somehow "tricky" but I think effectively.

...
manager.setLayout(layInfo);
// force WM_SIZE (resize) here!
...

Declaring the Real Components to Handle

This step associates the physical window handle of the component with its logical name given in the layout info. This is thought to be done once but it could be carried out more times. The components that appear in our layout info, and all the components associated with the dialog are to be added here. The layout manager shows or hides the components according to the layout info, but it has to know all of them.

Conclusions and Future Versions

In spite of its simplicity, this layout can do almost everything that is reasonably needed in normal applications. An improvement would be to allow easy composition of layouts, that is, allowing the layout info to reference not only components but also other layout info. This feature actually works for Java with EvaLayout; for C++ and Windows, I have an idea about how to do it. I hope that will come out in a next version soon.

Share

About the Author

I have a Telecomunications Engineering degree but since I learnt the first language (Pascal), almost I haven't stopped developing software. Mainly with C and C++ but I have touched many other languages and scripts. I use also to develop for fun (reinventing the wheel, of course!), currently almost all of such programs and tools are written in java (visit www.elxala.de).

If you say that for the discussion about "problems with the MFC version", it is already solved. In my last post of sources there is only one EvaLayoutManager class that can be used for both WinAPI or MFC applications. I believe that
this class contain the "concept", like you said.

Hi Ali,
you are right, it is a bug. The button "boton2" should at least
have the minimum height (row is A=Adapted). Even more, the same bug appears
also in my java version of EvaLayout (the original one), I will examine the
algorithm to see what happens in this case and hopefully I can report a
fixed version soon. Thank you for that!

Anyway, I am sure that you can achieve what you wanted with the current version.
For example if you wanted that the button "boton2" behaves like the "boton4" (expand vertically) it is enough to mark it as expandable (X). That is

...
X, boton2, +,,
...
Note that the line "A, +, +,," have actually no meaning. We tell to adapt the row to the given components but there are no components in this row! The same happens with the last column A (no component is to be found in the last column), you can simply remove it and the layout will be the same.

Nevertheless, a row or a column marked as expandable even with no component
at all might have a meaning. For instance, if you want that "boton2" expands
double than "boton4" then you can write :...
X, boton2, +,,
X, + , +,,
...

Finally if your intention was to make "boton2" bigger than "boton1" and "boton3" but not explandable you can achieve it with something like

After reviewing the code I have to conclude that the defect described is not a bug! The problem in this case is due to a wrong line in the layout info, specifically the line "A, +, +,,". In this line there is nothing to be adapted (A), no component begins in this line and causes an impredectible result (the no adaption of the component "boton2" in the previous line). It is enough to remove the line to make the layout work properly.
I tried to modify the algorithm to prevent possible superfluos lines like this in a layout info but finally I decided to not to do it. The reason is that the algorithm would increase in complexity, in my opinion, worthlessly.