Output Recording Contents Index Graph Formatting




17 Table Formatting

CLIM provides a mechanism for tabular formatting of arbitrary output.

To employ these facilities the programmer annotates some output-generating code with advisory macros that describe the high-level formatting constraints, for example, what parts of code produce a row of the table, what parts of that produce the cells in the row.

For example, the following produces a table consisting of three columns containing a number, its square, and its cube. The output can be seen in Figure 17.1 .

(defun table-test (count stream)
  (fresh-line stream)
  (formatting-table (stream :x-spacing '(3 :character))
    (dotimes (i count)
      (formatting-row (stream)
        (formatting-cell (stream :align-x :right)
          (prin1 i stream))
        (formatting-cell (stream :align-x :right)
          (prin1 (* i i) stream))
        (formatting-cell (stream :align-x :right)
          (prin1 (* i i i) stream))))))
Figure 17.1: Example of tabular output.
The general contract of these facilities is described in the next section.

17.1 Overview of Table Formatting Facilities

In general, table formatting involves a sharing of responsibilities between user-written code and CLIM code. Code that employs only the lower level output facilities has full control over ``where every piece of ink goes'' in the output. In contrast, code that employs CLIM's table formatting facilities passes control to CLIM at a higher level. The programmer benefits by being able to specify the appearance of output in more compact abstract terms, and by not having to write the code that constrains the output to appear in proper tabular form.

Tabular output consists of a rectangular array of pieces of output corresponding to the bounding rectangles of the output. Each piece of output forms the contents of a table cell . There is no restriction on the contents of a table cell; cells may contain text, graphics, even other tables. For purposes of this discussion, we draw a strong distinction between specifying what goes in a cell, and specifying how the cells are arranged to form a table.

Specifying the contents of a cell is the responsibility of the programmer. A programmer using the table formatting facilities can predict the appearance of any individual cell by simply looking at the code for that cell. A cell's appearance does not depend upon where in the table it lies, for instance. The only thing about a cell's appearance that cannot be predicted from that cell alone is the amount of space the table formatting has to introduce in order to perform the desired alignment.

Specifying the relative arrangements of cells to form a table is the responsibility of CLIM based on the advice of the programmer. The programmer advises CLIM about extra space to put between rows or columns, for instance, but does not directly control the absolute positioning of a cell's contents.

For purposes of understanding table formatting, the following model may be used.

Some tables are ``multiple column'' tables, in which two or more rows of the table are placed side by side (usually with intervening spacing) rather than all rows being aligned vertically. Multiple column tables are generally used to produce a table that is more esthetically pleasing, or to make more efficient use of space on the output device. When a table is a multiple column table, one additional step takes place in the formatting of the table: the rows of the table are rearranged into multiple columns in which some rows are placed side by side.

The advice that the programmer gives to CLIM on how to assemble the table consists of the following:

The advice describing how to place the contents of the cell within the cell consists of two pieces---how to constrain the cell contents in the horizontal direction, and how to constrain them in the vertical direction.

17.2 Table Formatting Functions

formatting-table(&optional stream &key x-spacing y-spacing multiple-columns multiple-columns-x-spacing equalize-column-widths (move-cursor t ) record-type &allow-other-keys ) &body body[Macro]
Binds the local environment in such a way the output of body will be done in a tabular format. This must be used in conjunction with formatting-row or formatting-column , and formatting-cell . The table is placed so that its upper left corner is at the current text cursor position of stream . If the boolean move-cursor is true (the default), then the text cursor will be moved so that it immediately follows the last cell of the table.

The returned value is the output record corresponding to the table.

stream is an output recording stream to which output will be done. The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-output* is used. body may have zero or more declarations as its first forms.

x-spacing specifies the number of units of spacing to be inserted between columns of the table; the default is the width of a space character in the current text style. y-spacing specifies the number of units of spacing to be inserted between rows in the table; the default is the default vertical spacing of the stream. Possible values for these two options option are:

multiple-columns is either nil , t , or an integer. If it is t or an integer, the table rows will be broken up into a multiple columns. If it is t , CLIM will determine the optimal number of columns. If it is an integer, it will be interpreted as the desired number of columns. multiple-columns-x-spacing has the same format as x-spacing . It controls the spacing between the multiple columns. It defaults to the value of the x-spacing option.

When the boolean equalize-column-widths is true , CLIM will make all of the columns have the same width (the width of the widest cell in any column in the entire table).

record-type specifies the class of output record to create. The default is standard-table-output-record . This argument should only be supplied by a programmer if there is a new class of output record that supports the table formatting protocol.

formatting-row(&optional stream &key record-type &allow-other-keys ) &body body[Macro]
Binds the local environment in such a way the output of body will be grouped into a table row. All of the output performed by body becomes the contents of one row. This must be used inside of formatting-table , and in conjunction with formatting-cell .

stream is an output recording stream to which output will be done. The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-output* is used. body may have zero or more declarations as its first forms.

Once a table has had a row added to it via formatting-row , no columns may be added to it.

record-type specifies the class of output record to create. The default is standard-row-output-record . This argument should only be supplied by a programmer if there is a new class of output record that supports the row formatting protocol.

formatting-column(&optional stream &key record-type &allow-other-keys ) &body body[Macro]
Binds the local environment in such a way the output of body will be grouped into a table column. All of the output performed by body becomes the contents of one column. This must be used inside of formatting-table , and in conjunction with formatting-cell .

stream is an output recording stream to which output will be done. The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-output* is used. body may have zero or more declarations as its first forms.

Once a table has had a column added to it via formatting-column , no rows may be added to it.

record-type specifies the class of output record to create. The default is standard-column-output-record . This argument should only be supplied by a programmer if there is a new class of output record that supports the column formatting protocol.

formatting-cell(&optional stream &key (align-x ':left ) (align-y ':baseline ) min-width min-height record-type &allow-other-keys ) &body body[Macro]
Controls the output of a single cell inside a table row or column, or of a single item inside formatting-item-list . All of the output performed by body becomes the contents of the cell.

stream is an output recording stream to which output will be done. The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-output* is used. body may have zero or more declarations as its first forms.

align-x specifies how the output in a cell will be aligned relative to other cells in the same table column. The default, :left , causes the cells to be flush-left in the column. The other possible values are :right (meaning flush-right in the column) and :center (meaning centered in the column). Each cell within a column may have a different alignment; thus it is possible, for example, to have centered legends over flush-right numeric data.

align-y specifies how the output in a cell will be aligned vertically. The default, :baseline , causes textual cells to be aligned along their baselines and graphical cells to be aligned at the bottom. The other possible values are :bottom (align at the bottom of the output), :top (align at the top of the output), and :center (center the output in the cell).

min-width and min-height are used to specify minimum width or height of the cell. The default, nil , causes the cell to be only as wide or high as is necessary to contain the cell's contents. Otherwise, min-width and min-height are specified in the same way as the :x-spacing and :y-spacing arguments to formatting-table .

record-type specifies the class of output record to create. The default is standard-cell-output-record . This argument should only be supplied by a programmer if there is a new class of output record that supports the cell formatting protocol.

formatting-item-list(&optional stream &key x-spacing y-spacing n-columns n-rows stream-width stream-height max-width max-height initial-spacing (row-wise t ) (move-cursor t ) record-type &allow-other-keys ) &body body[Macro]
Binds the local environment in such a way that the output of body will be done in an item list (that is, menu) format. This must be used in conjunction with formatting-cell , which delimits each item. The item list is placed so that its upper left corner is at the current text cursor position of stream . If the boolean move-cursor is true (the default), then the text cursor will be moved so that it immediately follows the last cell of the item list.

``Item list output'' is more strictly defined as: each row of the item list consists of a single cell. Rows are placed with the first row on top, and each succeeding row has its top aligned with the bottom of the previous row (plus the specified y-spacing ). Multiple rows and columns are constructed after laying the item list out in a single column. Item list output takes place in a normalized +y-downward coordinate system.

If row-wise is true (the default) and the item list requires multiple columns, each successive element in the item list is layed out from left to right. If row-wise is false and the item list requires multiple columns, each successive element in the item list is layed out below its predecessor, like in a telephone book.

The returned value is the output record corresponding to the table.

stream is an output recording stream to which output will be done. The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-output* is used. body may have zero or more declarations as its first forms.

x-spacing specifies the number of units of spacing to be inserted between columns of the item list; the default is the width of a #\Space character in the current text style. y-spacing specifies the number of units of spacing to be inserted between rows in the item list; the default is default vertical spacing of the stream. The format of these arguments is as for formatting-table .

When the boolean equalize-column-widths is true , CLIM will make all of the columns have the same width (the width of the widest cell in any column in the entire item list).

n-columns and n-rows specify the number of columns or rows in the item list. The default for both is nil , which causes CLIM to pick an aesthetically pleasing layout, possibly constrained by the other options. If both n-columns and n-rows are supplied and the item list contains more elements than will fit according to the specification, CLIM will format the item list as if n-rows were supplied as nil .

max-width and max-height constrain the layout of the item list. CLIM will not make the item list any wider than max-width , unless it is overridden by n-rows . It will not make the item list any taller than max-height , unless it is overridden by n-columns .

formatting-item-list normally spaces items across the entire width of the stream. When initial-spacing is true , it inserts some whitespace (about half as much space as is between each item) before the first item on each line. When it is false (the default), the initial whitespace is not inserted.

record-type specifies the class of output record to create. The default is standard-item-list-output-record . This argument should only be supplied by a programmer if there is a new class of output record that supports the item list formatting protocol.

format-itemsitems &key stream printer presentation-type x-spacing y-spacing n-columns n-rows max-width max-height cell-align-x cell-align-y initial-spacing (row-wise t ) (move-cursor t ) record-type[Function]
This is a function interface to the item list formatter. The elements of the sequence items are formatted as separate cells within the item list.

stream is an output recording stream to which output will be done. It defaults to *standard-output* .

printer must be a function that takes two arguments, an item and a stream, and outputs the item on the stream. printer has dynamic extent. The default for printer is prin1 .

presentation-type is a presentation-type. When printer is not supplied, the items will be printed as if printer were

#'(lambda (item stream)
    (present item presentation-type :stream stream))
When printer is supplied, each item will be enclosed in a presentation whose type is presentation-type .

x-spacing , y-spacing , n-columns , n-rows , max-width , max-height , initial-spacing , row-wise , and move-cursor are as for formatting-item-list .

cell-align-x and cell-align-y are used to supply :align-x and :align-y to an implicitly used formatting-cell .

record-type is as for formatting-item-list .

17.3 The Table and Item List Formatting Protocols

Both table and item list formatting is implemented on top of the basic output recording protocol, using with-new-output-record to specify the appropriate type of output record. For example, formatting-table first collects all the output that belongs in the table into a collection of row, column, and cell output records, all of which are children of a single table output record. During this phase, stream-drawing-p is bound to nil and stream-recording-p is bound to t . When all the output has been generated, the table layout constraint solver (adjust-table-cells or adjust-item-list-cells ) is called to compute the table layout, taking into account such factors as the widest cell in a given column. If the table is to be split into multiple columns, adjust-multiple-columns is now called. Finally, the table output record is positioned on the stream at the current text cursor position and then displayed by calling replay on the table (or item list) output record.

17.3.1 Table Formatting Protocol

Any output record class that implements the following generic functions is said to support the table formatting protocol.

In the following subsections, the term ``non-table output records'' will be used to mean any output record that is not a table, row, column, cell, or item list output record. When CLIM ``skips over intervening non-table output records'', this means that it will bypass all the output records between two such table output records (such as a table and a row, or a row and a cell) that are not records of those classes (most notably, presentation output records). CLIM implementations are encouraged to detect invalid nesting of table output records, such as a row within a row, a cell within a cell, or a row within a cell. Note that this does not prohibit the nesting of calls to formatting-table , it simply requires that programmers include the inner table within one of the cells of the outer table.

table-output-record[Protocol Class]
The protocol class that represents tabular output records; a subclass of output-record . If you want to create a new class that behaves like a table output record, it should be a subclass of table-output-record. Subclasses of table-output-record must obey the table output record protocol.
table-output-record-pobject[Predicate]
Returns true if object is a table output record , otherwise returns false .

:x-spacing[Init arg]
:y-spacing[Init arg]
:multiple-columns-x-spacing[Init arg]
:equalize-column-widths[Init arg]
All subclasses of table-output-record must handle these initargs, which are used to specify, respectively, the x and y spacing, the multiple column x spacing, and equal-width columns attributes of the table.

standard-table-output-record[Class]
The instantiable class of output record that represents tabular output. Its children will be a sequence of either rows or columns, with presentation output records possibly intervening. This is a subclass of table-output-record .

map-over-table-elementsfunction table-record type[Generic function]
Applies function to all the rows or columns of table-record that are of type type . type is either :row , :column , or :row-or-column . function is a function of one argument, an output record; it has dynamic extent. map-over-table-elements is responsible for ensuring that rows, columns, and cells are properly nested. It must skip over intervening non-table output record structure, such as presentations.

adjust-table-cellstable-record stream[Generic function]
This function is called after the tabular output has been collected, but before it has been replayed. The method on standard-table-output-record implements the usual table layout constraint solver (described above) by moving the rows or columns of the table output record table-record and the cells within the rows or columns. stream is the stream on which the table is displayed.

adjust-multiple-columnstable-record stream[Generic function]
This is called after adjust-table-cells to account for the case where the programmer wants the table to have multiple columns. table-record and stream are as for adjust-table-cells .

17.3.2 Row and Column Formatting Protocol

Any output record class that implements the following generic functions is said to support the row (or column) formatting protocol.

row-output-record[Protocol Class]
The protocol class that represents one row in a table; a subclass of output-record . If you want to create a new class that behaves like a row output record, it should be a subclass of row-output-record. Subclasses of row-output-record must obey the row output record protocol.
row-output-record-pobject[Predicate]
Returns true if object is a row output record , otherwise returns false .

standard-row-output-record[Class]
The instantiable class of output record that represents a row of output within a table. Its children will be a sequence of cells, and its parent (skipping intervening non-tabular records such as presentations) will be a table output record. This is a subclass of row-output-record .

map-over-row-cellsfunction row-record[Generic function]
Applies function to all the cells in the row row-record , skipping intervening non-table output record structure. function is a function of one argument, an output record corresponding to a table cell within the row; it has dynamic extent.

column-output-record[Protocol Class]
The protocol class that represents one column in a table; a subclass of output-record . If you want to create a new class that behaves like a column output record, it should be a subclass of column-output-record. Subclasses of column-output-record must obey the column output record protocol.
column-output-record-pobject[Predicate]
Returns true if object is a column output record , otherwise returns false .

standard-column-output-record[Class]
The instantiable class of output record that represent a column of output within a table. Its children will be a sequence of cells, and its parent (skipping intervening non-tabular records such as presentations) will be a table output record; presentation output records may intervene. This is a subclass of column-output-record .

map-over-row-cellsfunction column-record[Generic function]
Applies function to all the cells in the column column-record , skipping intervening non-table output record structure. function is a function of one argument, an output record corresponding to a table cell within the column; it has dynamic extent.

17.3.3 Cell Formatting Protocol

Any output record class that implements the following generic functions is said to support the cell formatting protocol.

cell-output-record[Protocol Class]
The protocol class that represents one cell in a table or an item list; a subclass of output-record . If you want to create a new class that behaves like a cell output record, it should be a subclass of cell-output-record. Subclasses of cell-output-record must obey the cell output record protocol.
cell-output-record-pobject[Predicate]
Returns true if object is a cell output record , otherwise returns false .

:align-x[Init arg]
:align-y[Init arg]
:min-width[Init arg]
:min-height[Init arg]
All subclasses of cell-output-record must handle these initargs, which are used to specify, respectively, the x and y alignment, and the minimum width and height attributes of the cell.

standard-cell-output-record[Class]
The instantiable class of output record that represent a single piece of output within a table row or column, or an item list. Its children will either be presentations, or output records that represent displayed output. This is a subclass of cell-output-record .

cell-align-xcell[Generic function]
cell-align-ycell[Generic function]
cell-min-widthcell[Generic function]
cell-min-heightcell[Generic function]
These functions return, respectively, the x and y alignment and minimum width and height of the cell output record cell .

17.3.4 Item List Formatting Protocol

item-list-output-record[Protocol Class]
The protocol class that represents an item list; a subclass of output-record . If you want to create a new class that behaves like an item list output record, it should be a subclass of item-list-output-record. Subclasses of item-list-output-record must obey the item list output record protocol.
item-list-output-record-pobject[Predicate]
Returns true if object is an item list output record , otherwise returns false .

:x-spacing[Init arg]
:y-spacing[Init arg]
:initial-spacing[Init arg]
:row-wise[Init arg]
:n-rows[Init arg]
:n-columns[Init arg]
:max-width[Init arg]
:max-height[Init arg]
All subclasses of item-list-output-record must handle these initargs, which are used to specify, respectively, the x and y spacing, the initial spacing, row-wise, the desired number of rows and columns, and maximum width and height attributes of the item list.

standard-item-list-output-record[Class]
The instantiable output record that represents item list output. Its children will be a sequence of cells, with presentations possibly intervening. This is a subclass of item-list-output-record .

map-over-item-list-cellsfunction item-list-record[Generic function]
Applies function to all of the cells in item-list-record . map-over-item-list-cells must skip over intervening non-table output record structure, such as presentations. function is a function of one argument, an output record corresponding to a cell in the item list; it has dynamic extent.

adjust-item-list-cellsitem-list-record stream[Generic function]
This function is called after the item list output has been collected, but before the record has been replayed. The method on standard-item-list-output-record implements the usual item list layout constraint solver. item-list-record is the item list output record, and stream is the stream on which the item list is displayed.




Output Recording Contents Index Graph Formatting