## 11.5 Tabular layout

XPCE provides various mechanisms for two-dimensional layout.

- Controller layout using `device`->`layout_dialog'
  This method is used by the classes dialog and dialog_group. It knows about layout requirements in controller windows, such as alignment of label- and value-width in stacked controllers. etc. Layout of controllers is described in chapter 4.

- Simple tabular layout using format
  In instance of class format can be attached to a device using `device`->`format'. This causes the device to place its graphicals according to the specification in the format object. This technique is frequently used to label images, place images in an image browser, etc. See section 11.5.1.

- Full table support using table
  An instance of table can be associated with a device to realise modern tables using the same primitives as defined in HTML-3: row- and column spanning, alignment, spacing, rules and borders, etc. The library `library(tabular)` provides a user-friendly front-end for most of the functionality of class table.

### 11.5.1 Using format

Class format can be seen as a poor-mens version of table. On the other hand, there are two cases that still make it a valuable solution. One is to deal with simple compound graphicals, such as a bitmap with a label displayed below it. The other is for browsing collections of graphical objects such as images.

The class icon below displays a label-text below an image.

    :- pce_begin_class(icon, device).

    :- pce_global(@icon_format, make_icon_format).

    make_icon_format(F) :-
            new(F, format(horizontal, 1, @on)),
            send(F, adjustment, vector(center)),
            send(F, row_sep, 2).

    initialise(Icon, Img:image, Label:name) :->
            send_super(Icon, initialise),
            send(Icon, format, @icon_format),
            send(Icon, display, bitmap(Img)),
            send(Icon, display, text(Label, center)).

    :- pce_end_class.

An example using format for distribution graphicals over a window is the library `library(pce_image_browser)`.

### 11.5.2 Using table using the ``tabular'' library

The class table acts much the same way as class format in the sense that it is attached to a device and modifies the layout management of this device. For this purpose it uses an interface defined in XPCE version 5.0 and realised using the methods `device`<->`layout_manager' and `graphical`<->`layout_interface'. Figure 22 gives an overview of the classes realising tabular layout.

Figure 22 : Layout manager interface for tables

The advantage of the approach using layout manager objects is that they can easily be associated with any subclass of device, such as a window. The disadvantage is that the communication gets more difficult due to the different objects involved. This complication is hidden in the XPCE/Prolog class tabular, a subclass of device with an associated table and methods for guiding the messages for common usage.

tabular ->initialise:
  Create a device with associated table.
tabular ->append:
  Append a new cell. Cells are places left-to-right. The arguments are:

  - Label
    Defines the content. It this is a name, a text is created. Otherwise the graphical is immediately placed in the table.

  - Font
    Defines the font if a text is created from a Label of type name.

  - HAlign
    Horizontal alignment. When omitted, the value from the corresponding table_column is used.

  - VAlign
    Vertical alignment. When omitted, the value from the corresponding table_row is used.

  - Colspan
    Number of columns spanned. Default is 1.

  - Rowspan
    Number of rows spanned. Default is 1.

  - Background
    Colour or pattern used to fill the background of the cell. When omitted, the value from row or column is used or the background is left untouched.

  - Colour
    Defines the default foreground colour when painting the cell's graphical. When omitted, the row, column and finally device are tried.
tabular ->append_label_button: Field:name
  This method appends a button that is nicely aligned with the cell. If the button is depressed it activates `->`sort_rows, providing the column index and the row below the row holding the button.
tabular ->sort_rows: Col:int, Row:int
  A virtual method with a body that prints an informative message. It is called from a button installed using `->`append_label_button and receives the column to sort-on as well as the first row to sort.
tabular <-table:
  Table Returns the table serving as `<-`layout_manager.
tabular ->table_width: Width:int
  Force the table to perform the layout in the indicated width. Initially the width of a tabular is defined by the content. Setting the width forces the table to negotiate with its columns and then force the width of the columns.
tabular ->event: Event:event
  This refinement of `device`->`event' determines the cell in which the event occurs. If this cell has a `cell`<->`note_mark' attached and the graphical defines the method `->`on_mark_clicked, the event is checked against the mark-image. Otherwise the event is forwarded to the graphical inside the cell, even it it doesn't occur in the area of the graphical, making small (text-)objects sensitive to all events in the cell. Finally, this method checks for attempts to drag the column-borders, changing the layout of the table.

As tabular delegates all messages not understood to the `<-`table, the messages of this class are also available. Below are the most important ones.

table ->next_row: EndGroup:[bool]
  Start the next row in the table. If EndGroup is @on, the just-finished row is marked to end a row-group. See also `->`rules.
table ->border: Border:0..
  Defines the thickness of border and rule-lines. Default is 0, not drawing any lines.
table ->frame: {void,above,below,hsides,vsides,box}
  Defines which parts of the box around the table are painted (if `<-`border > 0). The terminology is from HTML-3.
table ->rules: {none,groups,rows,cols,all}
  Defines which lines between rows/columns are painted (if `<-`border > 0). The terminology is from HTML-3.
table ->cell_padding: Padding:int`|`size
  Defines the space around the content of a cell. If this is an integer this space is the same in horizontal and vertical directions. If it is a size these can be specified independently.
table ->cell_spacing: Spacing:int`|`size
  Defines the distance between the cells. Same rules as for `->`cell_padding applies. In some cases pretty effects can be achieved setting this value to minus the `<-`border.

Below we build a small example.

    :- use_module(library(tabular)).
    :- use_module(library(autowin)).

    make_table :-
            new(P, auto_sized_picture('Table with merged cells')),
            send(P, display, new(T, tabular)),
            send(T, border, 1),
            send(T, cell_spacing, -1),
            send(T, rules, all),
            send_list(T,
                      [ append(new(graphical), rowspan := 2),
                        append('Length/mm', bold, center, colspan := 3),
                        next_row,
                        append('body', bold, center),
                        append('tail', bold, center),
                        append('ears', bold, center),
                        next_row,
                        append('males', bold),
                        append('31.4'),
                        append('23.7'),
                        append('3.8'),
                        next_row,
                        append('females', bold),
                        append('29.6'),
                        append('20.8'),
                        append('3.4')
                      ]),
            send(P, open).

Figure 23 : Small table with row/column spanning