Click here to Skip to main content
15,860,859 members
Articles / Web Development / HTML

EvaLayout, Lay It Be!

Rate me:
Please Sign up or sign in to vote.
4.93/5 (58 votes)
23 May 2017CPOL7 min read 186.9K   4.3K   114   47
An efficient and flexible layout manager

Who's gonna layout this?

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. The concepts of columns, rows, filling space, spanning columns and rows, etc. is the basically the same in all these systems. 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:

EvaLayout, 10, 10, 5, 5

grid,    75    ,    X    ,    A   ,
   A, boton1   , memo    ,    -   ,
   A, boton2   ,   +     ,        ,
   A, boton3   ,   +     ,        ,
   X,          ,   +     ,        ,
   A, text1    ,   -     , boton4 ,

describes a layout with:

  • 10 pixels of left, right, upper, and bottom margins
  • 5 pixels of horizontal and vertical gaps
  • A first column of 75 pixels, a second one expandable, and a third one adaptable
  • Five rows, all adaptable except the one that is expandable
  • A memo component that spans vertically 3 rows and horizontally 1 column
  • A text component that spans horizontally 1 column

The whole design could look like:

design layout

and the resultant dialog is:

resultant dialog

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 an 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):

C++
#include "EvaLayoutManager.h"

#include "EvaLine.h"
#include "EvaUnit.h"
#include "EvaFile.h"
...

// to load layout info from a file
EvaFile eFile;
// to load layout info from a file
// or to store more layout info's
EvaUnit eUnit;
// layout info object
Eva     eLayoutInfo;

// the layout manager
EvaLayoutManager manager;

We divide the steps to use EvaLayoutManager, in four:

  • Preparing or loading the layout Info
  • Setting the layout info into the manager
  • Declaring the real components to handle
  • Doing the layout (positioning and resizing the components)

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:

  1. Directly:
    C++
    BOOL CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
       ...
          case WM_INITDIALOG:
          {
             Eva layInfo;
             layInfo.addLine (EvaLine ("EvaLayout, 10, 10, 5, 5"));
             layInfo.addLine (EvaLine ("  grid,    75    ,    X    ,    A   ,"));
             layInfo.addLine (EvaLine ("     A, boton1   , memo    ,    -   ,"));
             layInfo.addLine (EvaLine ("     A, boton2   ,   +     ,        ,"));
             layInfo.addLine (EvaLine ("     A, boton3   ,   +     ,        ,"));
             layInfo.addLine (EvaLine ("     X,          ,   +     ,        ,"));
             layInfo.addLine (EvaLine ("     A, edit1    ,   -     , boton4 ,"));
           ...
  2. From a file (Eva format, see the file WinLayouts.eva in the demo project):
    C++
    BOOL CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
       ...
          case WM_INITDIALOG:
          {
             EvaFile eFile;
             EvaUnit eUnit;
             Eva     eLayInfo;
             
             eFile.load (eUnit, "WinLayouts.eva", "data");
             layInfo = eUnit[0];
           ...

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.

C++
...
   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.

C++
manager.removeComponents(); // if appropriate

manager.addComponent("memo",    GetDlgItem(hDlg, ID_MEMO));
manager.addComponent("boton1",  GetDlgItem(hDlg, ID_BUTTON_1));
manager.addComponent("boton2",  GetDlgItem(hDlg, ID_BUTTON_2));
manager.addComponent("boton3",  GetDlgItem(hDlg, ID_BUTTON_3));
...

Doing the Layout (Positioning and Resizing the Components)

It should be enough to do it in the WM_SIZE message handler.

C++
BOOL CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, 
              WPARAM wParam, LPARAM lParam)
{
   ...
      case WM_SIZE:
         {
            manager.doLayout(wParam, lParam);
         }
         break;

Version 4 Composition and Masking Components

This version adds two new features to the C++ EvaLayout library that makes defining complex layoutsmuch more easier and permits changing dynamically not only all but also a part of the layout.

Composition of Layouts

Given that we pass to the manager several layouts (or layout info). By composition, it is meant that a layout can reference not only components but also another layout and this will be resolved by the manager automatically. This facilitates a lot defining complex layout by dividing it into smaller pieces.

Component Mask Mechanism

A new function in the class EvaLayoutManager called maskElement permits the replacement of one component (widget or layout) by another one. In other words, the ability of changing a part of the window dynamically in a straightforward way.

Both features are shown in the demo included in the EvaLayoutV4 download.

Version JavaScript

This JavaScript version of EvaLayout has the same features, composition and masking, as the C++ version 4. In fact, it was derived from the last one.

I have to thank Domingo Alvarez, who had the initiative of translating the very first version of C++ Evalayout to JavaScript in his Github project, https://github.com/mingodad/eva-layout-js.

In the attached samples, an intermediate version of JavaScript evalayout is used, the most updated one is maintained in the github project gastona under META-GASTONA/js.

HTML code of a simple example using Evalayout js.

HTML
<html>
  <body>

      <!-- elements will be arranged by layout manager -->

      <button id="bButton1">Boton 1</button>
      <button id="bButton2">Boton 2</button>
      <textarea id="xText">Text area</textarea>

   <script src="Eva.js"> </script>
   <script src="EvaLayout.js"> </script>
   <script src="LayoutManager.js"> </script>

   <script>

     var layoutText = function () {
     /*
       #layouts#

          <main>
             Evalayout, 10, 10, 20, 20
                --- , X       ,   X
                    , bButton1, bButton2
                 X  , xText   , -

     #**#
     */
     }.toString ();

   var managr = layoutManager (evaFileStr2obj (layoutText));
   managr.doLayout (500, 400);

  </script>
</body>
</html>

and the result in the browser:

Image 4

Also included is a small interactive example, changing the layout dynamically using the mask method.

All samples are very simple, just play with them adding more elements and layouts, it can handle everything!

Conclusions and Other Versions

Evalayout is simple and flexible and it is available in Java, C++ (this article) and JavaScript.

Specifically, the open source projects gastona and jGastona available here on github use Evalayout in conjunction with other libraries too, not only arrange the components, but to generate them on the fly. The article Http sweet Http (with gastona) shows how this can be used in small http applications for generating the GUI using Java in the server and JavaScript in the client.

This picture from the article illustrates the client (browser) part:

Image 5

History

  • 22.04.2006 - First release
  • 02.01.2008 - Fixed some bugs and added a cleaner MFC example
  • 21.01.2016 - Version4 Layout composition and Mask mechanism
  • 06.08.2016 - Version JavaScript

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
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).

Comments and Discussions

 
QuestionNice I just wonder Pin
megaadam31-Dec-17 0:17
professionalmegaadam31-Dec-17 0:17 
AnswerRe: Nice I just wonder Pin
Alejandro Xalabarder12-Feb-18 11:07
Alejandro Xalabarder12-Feb-18 11:07 
Questioncould you share more details on your Layout algorithm? Pin
Southmountain19-Mar-17 14:03
Southmountain19-Mar-17 14:03 
AnswerRe: could you share more details on your Layout algorithm? Pin
Alejandro Xalabarder2-Apr-17 12:07
Alejandro Xalabarder2-Apr-17 12:07 
GeneralRe: could you share more details on your Layout algorithm? Pin
Southmountain27-May-17 10:41
Southmountain27-May-17 10:41 
PraiseKeep up with good work Pin
Huzifa Terkawi18-Dec-16 20:20
Huzifa Terkawi18-Dec-16 20:20 
GeneralMy vote of 5 Pin
eslipak6-Sep-16 11:35
professionaleslipak6-Sep-16 11:35 
QuestionNew Version released Pin
Alejandro Xalabarder20-Jan-16 13:21
Alejandro Xalabarder20-Jan-16 13:21 
BugCComboBox can not be pull down if... Pin
dunniu29-Jul-15 3:38
dunniu29-Jul-15 3:38 
GeneralRe: CComboBox can not be pull down if... Pin
dunniu30-Jul-15 19:58
dunniu30-Jul-15 19:58 
GeneralRe: CComboBox can not be pull down if... Pin
Alejandro Xalabarder21-Oct-15 11:04
Alejandro Xalabarder21-Oct-15 11:04 
GeneralRe: CComboBox can not be pull down if... Pin
Alejandro Xalabarder20-Jan-16 13:15
Alejandro Xalabarder20-Jan-16 13:15 
GeneralRe: CComboBox can not be pull down if... Pin
dunniu18-Feb-16 18:25
dunniu18-Feb-16 18:25 
GeneralMy vote of 5 Pin
tang100071-Aug-12 3:42
tang100071-Aug-12 3:42 
GeneralMy vote of 5 Pin
Rajiv Bhagwat26-Jul-12 4:39
professionalRajiv Bhagwat26-Jul-12 4:39 
GeneralDesign idea Pin
v_srinu_26_f25-Apr-09 17:24
v_srinu_26_f25-Apr-09 17:24 
GeneralRe: Design idea [modified] Pin
Alejandro Xalabarder29-Apr-09 9:33
Alejandro Xalabarder29-Apr-09 9:33 
QuestionAlignment within a cell for component (L C R FILL T C B FILL) Pin
v_srinu_26_f25-Apr-09 17:15
v_srinu_26_f25-Apr-09 17:15 
AnswerRe: Alignment within a cell for component (L C R FILL T C B FILL) [modified] Pin
Alejandro Xalabarder29-Apr-09 8:51
Alejandro Xalabarder29-Apr-09 8:51 
GeneralA Bug! Pin
Ali Khanlarkhani5-Nov-07 3:07
Ali Khanlarkhani5-Nov-07 3:07 
GeneralRe: A Bug! Pin
Alejandro Xalabarder6-Nov-07 12:21
Alejandro Xalabarder6-Nov-07 12:21 
GeneralIt is not a bug Pin
Alejandro Xalabarder29-Dec-07 10:11
Alejandro Xalabarder29-Dec-07 10:11 
NewsBug fix: memory leak and code for MFC Pin
$@m10-Jun-07 6:04
$@m10-Jun-07 6:04 
NewsAnother solution Pin
$@m10-Jun-07 23:09
$@m10-Jun-07 23:09 
GeneralRe: Bug fix: memory leak and code for MFC Pin
Alejandro Xalabarder6-Nov-07 13:13
Alejandro Xalabarder6-Nov-07 13:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.