Back to Contents


Form Rendering

Summary:


Introduction

Genero has introduced a form rendering system. Forms are not based on fixed text-mode screen, but can display complex layouts. In order to support .per form definition files, the rendering system has to manage a character-based definition, which implies very specific graphical rules. This document explains the graphical rendering of a .per form.


A character-based grid

Note that SCROLLGRID and Groups (without GRIDCHILDRENINPARENT attribute) behave the same way as Grids.

The grid container is the most important container - it contains all 'final' widgets (fields, buttons, etc). The .per file defines a form which is character based; each character defines a cell of the grid:

GRID
{
First Name [fname  ]
Last Name  [lname  ]
}
END 

Above .per file layout specification can be show in a character grid as follows:

With a fixed-font based front end, there is no problem, but Genero introduced Windows look and feel and proportional fonts. Objects are then created and added to the grid; each object has a starting position (defined by posX and posY attributes) and the number of cells taken (gridWidth, gridHeight attributes).

Grid layout rules

Front-ends grid layout follows these important rules:

  1. The position of the widgets is defined by the posX and posY AUI attributes, while the gridWidth and gridHeight AUI attributes are used to define their width and height in cell units.
  2. Empty lines and empty columns take 0 pixels.
  3. The size of a cell depends on the size of the widgets inside the grid.
  4. Widget's minimum size is computed via its size and the SAMPLE attribute. The size of a widget is defined by the width and height attributes in the AUI tree.
  5. The preferred size of the widget is computed according to the SIZEPOLICY attribute.
  6. The final widget size is computed according to the minimum and preferred size, to fill the cells in the grid.
  7. A small spacing is applied in non-empty cells.

The next screenshot shows 2 labels and 2 fields placed in a grid:

 

Character set usage

The character set used to edit and compile .per form files is defined by the current locale. Form elements (typically, labels) can be written with non-ASCII characters of the current codeset. The form element positions and sizes are determined by counting the width of characters, rather than the number of bytes identifying the characters in the current codeset. This rule can be ignored when using a single-byte character set such as ISO-8859-1 or CP-1252, where each character has width of 1 and codepoint of 1 byte. But this is important when using a multi-byte character set like BIG5 or UTF-8.

For example, in the UTF-8 multi-byte codeset, a Chinese ideogram is encoded with three bytes, while the visual width of the character is twice the size of a Latin character. In the next example, the labels with three Chinese characters have the same width as the labels using six Latin characters. As a result, the labels will get the same size (6 cells), and all fields will be aligned properly in the GUI form:

GRID
{
叽哱唶 [f001  ]   abcdef [f002  ]
abcdef [f003  ] 叽哱唶 [f004  ]   
}
END

Note however that it is recommended to write all .per files in ASCII codeset, and use Localized Strings to internationalize your forms.

Complex example

This Grid contains several fields.

For each field, the position and the number of cells is computed by the form compiler. Then the front-end creates the widgets and sets them on the grid.

Once widgets are on the grid, their minimum size is computed according to their size, to SIZEPOLICY and the SAMPLE attributes. Then the grid cells are computed.

You can see that fields k and c are much bigger than expected:

Some fields are proportionally bigger than others because some parameters are variable, while others are fixed. The width of the widget is the sum of border width, plus the content width (depending on SIZEPOLICY and the SAMPLE attributes).

Note that since the default SAMPLE is MMMMMM000..., the graphical width of a field is not linearly proportional to the width defined in the form file. For example, a field of 1 will be as wide as 2 borders + 1 'M'. A field of 10 will be as wide as 2 borders + 6 'M' + 4 '0'. This means that a field of 1 is far from being 10 times smaller than a field of 10.


Grid dependencies

The example below illustrates how widgets are dependent from each-other inside the grid (This is useful to keep text-mode alignment):

GRID
{
  [a      ]
  [b      ]
}
END

This .per implies that a and b start at the same position and have the same size, whatever a and b are.

A large number of cells for large widgets

This rule could lead to very different results, especially when a large widget is assigned into a small number of cells.

Example:

LAYOUT
GRID
{
[a|b   ][f     ]
[c|d]   [e     ]
}
END
END

ATTRIBUTES
CHECKBOX a = formonly.a, TEXT="A Checkbox";
EDIT b = formonly.b;
EDIT c = formonly.c;
CHECKBOX d = formonly.d, TEXT="Another Checkbox";
EDIT e = formonly.e;
EDIT f = formonly.f;
END

As seen previously, the grid will be computed regarding characters:

Then the minimum size of each widget and the layout is computed. Cells (0,1) and (1,3) contain a checkbox; these checkboxes will enlarge columns 1 and 3.

 As Edit "c" is defined to have the same width as checkbox "a", it will be much larger as expected: 

To avoid this visual result, you must assign a realistic number of cells for each object:

GRID
{
[a        |b   ][f     ]
[c|d           ][e     ]
}

Even if the LAYOUT section is wider, the result will be smaller:

HBox Tags

Mechanism

To get rid of the character-based grid, HBox Tags have been introduced. This mechanism defines a widget container that will gather the widget horizontally, like the HBOX layout container. All widgets inside this container are no longer dependent on the parent grid:

GRID
{
[a:b:c   ]
[d|e|f   ]
}
END

Using a : colon in an item tag defines an HBox Tag: An HBox container is created and will contain widgets a, b and c. These widgets won't be aligned in the Grid:

This mechanism is useful when you have large widgets in a small number of cells in one row and don't want to have dependencies:

If we take the form3 example again, and modify it with HBox Tags:

GRID
{
[a:b   ][f     ]
[c:d   ][e     ]
}
END

Spacer Items in HBox tags

HBox tags also introduces the SpacerItems concept: when a grid HBox is created, the content may be smaller than the container:

Because of the checkbox, the cell 1 is very large, and then the HBox is larger than the three fields. A SpacerItem object is automatically created by the form compiler; the role of the SpacerItem is to take all the free space in the container. Then all the widgets are packed at the left.

By default, a SpacerItem is created at the right of the container, but the spacer can also be defined in another place:

GRID
{
[a       :b       :c       ] <- default: spacer on the right
[ :d     :e       :f       ] <- spacer on the left
[g       :      :h         ] <- spacer between g and h
[i: :j: :k      : :l       ] <- multiple spacers (between i and j, j and k, k and l
}
END


Packed Grid

General rule

When you resize a window, the content will either grow with the window or be packed in the top left position. The rule followed by the front-end is that the grid is packed (horizontally / vertically / both) if nothing can grow in that direction.

The following widgets can grow horizontally:

The following widgets can grow vertically:

Group exception

In general, a GRID can grow if any object inside the GRID can grow.

The exception to this rule: If there is only one GROUP (defined without the GRIDCHILDRENINPARENT attribute) inside a GRID and nothing else, the grid can grow.

This exception allows better rendering of a grouped grid:


Automatic Horizontal and Vertical Boxes

When using layout tags in a GRID container, the fglform compiler will automatically add HBox or VBox containers with splitter in the following conditions:

Stretchable elements are containers such as TABLEs, or form items like IMAGEs, TEXTEDITs with STRETCH attribute.

Note that no HBox or VBox will be created if the elements are in a SCROLLGRID container.

The example below defines two tables stacked vertically, generating a VBox with splitter (note that ending tags are omitted):

01 <T table1         >
02 [colA  |colB      ]
03 [colA  |colB      ]
04 [colA  |colB      ]
05 [colA  |colB      ]
06 <T table2         >
07 [colC  |colD      ]
08 [colC  |colD      ]

Below the layout defines two stretchable TEXTEDITs placed side by side which would generate an automatic HBox with splitter. Note that to make both textedits touch you need to use a pipe delimiter in between:

01 [textedit1         |textedit2                ]
02 [                  |                         ]
03 [                  |                         ]
04 [                  |                         ]

For more details, see Layout Tags in the Form Specification File page.