4.3 Layout in dialog windows

The layout inside a dialog window may be specified by two means, either using pixel-coordinates or using symbolic layout descriptions. The latter is strongly encouraged, both because it is generally much easier and because the layout will work properly if the end-user uses different preferences (see chapter 8) than the application developer.

The following methods can be used to define the layout of a dialog. All methods actually have both send- and get-versions. The methods listed only as `->send' methods are unlikely to be used as get-methods in application code.

dialog_item ->above: dialog_item
dialog_item ->below: dialog_item
dialog_item ->left: dialog_item
dialog_item ->rigth: dialog_item
These relations built a two-dimensional grid of dialog-items and determine the relative positioning of the dialog items. It suffices to relate each dialog item to one other item.
device ->append_dialog_item: graphical, [{below,right,next_row}]
dialog ->append: graphical, [{below,right,next_row}]
Append a dialog item relative to the last one appended. This method is the principal methods used to fill dialog windows. For the first item, the last argument is ignored. If the last argument is below, this item is placed below the previous one. If the argument is right, it is placed right of the previous one and if the argument is next_row, the item is placed below the first one of the current row of dialog items. If the last argument is @default, dialog objects are placed next_row, except for buttons, which are placed in rows, left to right.
dialog ->gap: size
Defines the distance between rows and columns of items as well as the distance between the bounding box of all items and the window border.
dialog_item <->reference: point
Point relative to the top-left corner that defines the reference-point of the dialog item. If two items are aligned horizontally or vertically, it are actually their reference points that are aligned.
dialog_item ->alignment: {column,left,center,right}
This attribute controls how items are aligned left-to-right in their row. An item with ->alignment: column will be alignment horizontally using the references of its upper or lower neighbour. Horizontally adjacent items with the same alignment will be flushed left, centered or flushed right if the alignment is one of left, center or right. The alignment value is normally specified as a class-variable and used to determine the layout of rows of button objects.
dialog_item ->hor_stretch:
0..100 After completing the initial layout, possibly remaining horizontal space is distributed proportionally over items that return a non-zero value for this attribute. By default, class text_item yields 100 for this value, normally extending text_items as far as possible to the right.

The methods above deal with the placement of items relative to each other. The methods below ensure that columns of items have properly aligned labels and values.

dialog_item <->label_width: [0..]
If the item has a visible label, the label_width is the width of the box in which the label is printed. The dialog layout mechanism will align the labels of items that are placed above each other if <-auto_label_align is @on. The argument @default assigns the minimum width of the label, the width required by the text of the label.
dialog_item <->label_format: {left,center,right}
Determines how the label is aligned in its box. The values are left, center and right. This value is normally defined by the look and feel.
dialog_item <->value_width: [0..]
If the item displays multiple values left-to-right (only class menu at the moment), `dialog_item->value_width' is used to negotiate equal width of the value-boxes similar to ->label_width if <-auto_value_align is @on.

The methods listed below activate the layout mechanism. Normally, only `device->layout_dialog' needs to be called by the user.

dialog ->layout: [size]
device ->layout_dialog: gap=[size], size=[size], border=[size]
Implements the dialog layout mechanism. `Dialog->layout' simply calls `device->layout_dialog' using `dialog<-gap'. `Device->layout_dialog' first uses the <-above, etc. attributes to build a two-dimensional array of items. Next, it will align the labels and value of items placed in the same column. Then it will determine the size and reference point for each of the items and determine the cell-size. It will then align all items vertically and afterwards horizontally, while considering the `dialog_item<-alignment'.
dialog ->_compute_desired_size:
Sent from `frame->fit' to each of the member windows. For class dialog, this activates ->layout and then computes the desired size of the window.

4.3.1 Practical usage and problems

Most of the above methods are only used rarely for fine-tuning the layout. Almost all dialog windows used in the development environment, demo applications and Prolog library simply use `dialog->append', sometimes specifying the last argument.

Two problems are currently not taken care of very well. Aligning multiple objects with a single third object can only be achieved using a sub-dialog in the form of a device and often requires some additional messages. The dialog of figure 9 is created using the following code:

layoutdemo1 :-
        new(D, dialog('Layout Demo 1')),
        send(D, append,
             new(BTS, dialog_group(buttons, group))),
        send(BTS, gap, size(0, 30)),
        send(BTS, append, button(add)),
        send(BTS, append, button(rename), below),
        send(BTS, append, button(delete), below),
        send(BTS, layout_dialog),
        send(D, append, new(LB, list_browser), right),
        send(D, append, new(TI, text_item(name, ''))),
        send(LB, alignment, left),
        send(D, layout),
        send(LB, bottom_side, BTS?bottom_side),
        send(LB, right_side, TI?right_side),
        send(D, open).

Figure 9 : Aligning multiple items

In line 3, a device is added to the dialog to contain the stack of buttons. This device is sent an explicit ->layout_dialog to position the buttons. Next, the list_browser is placed to the right of this stack and the text_item on the next row.

If you try this layout, the first column will hold the device and the text_item and the list_browser will be placed right of this column and thus right of the text_item. Using `dialog_item->alignment: left' enforces the list_browser to flush left towards the device. Now we enforce the layout and adjust the bottom and right sides of the list_browser to the device and text_item.

Dialog windows do not reposition their contents if the window is resized in the current implementation. If the window is enlarged, the items stay in the top-left corner. If the window is made smaller, part of the items may become invisible. Resizing can be implemented by the user by trapping the `window->resize_message'.