# The FormsVBT Language

The FormsVBT language provides a mechanism for textually describing a user interface. The language is not a general-purpose programming language. It has no variables, control structure, or runtime computation. Rather, it's a declarative textual description of the hierarchical arrangement of components that make up the user interface, written as an S-expression. Fig. [fig:horn] shows a simple user interface and its S-expression.

## Basic Syntax

Each component is written as an S-expression that begins with type of the component, such as `Border`, `Button`, or `VBox`. Following the type are subexpressions that describe eitherproperties or children (sub-components). Properties provide additional information that control the appearance or behavior of the component. The S-expression in Fig. [fig:horn] contains properties `Pen`, `Pattern`, `Width`, `Height`, `BgColor`, and `Color`. Property-expressions are distinguished from child-expressions by their names. There is one important rule to remember:

> In any S-expression, all property expressions must appear before any sub-components.

Properties are discussed in detail in Section [sec:language-properties] .

    (Border (Pen 20) (Pattern "NWDiagonal")
      (Button %cornet
        (VBox
          (Shape (Width 50) (Height 40)
            (Pixmap "Trumpet"))
          (Text (BgColor "Black") (Color "White") "Horn"))))

A very simple user interface and its description in the FormsVBT language. The user interface consists of a button that is surrounded by a border. The button itself displays a pixmap of a trumpet above the word ``Horn''. At runtime, the application will register an event-handler for the component named ``cornet''; the event-handler will be invoked when the user clicks on the button.

## Components

The components of FormsVBT can be categorized in two ways: by the number of children that they take, or by their function. In the first categorization, we have leaves, filters, and splits:

- A leaf has no children.
- A filter has exactly one child.
- A split contains any number of children.

In Fig. [fig:horn] , `Text` and `Pixmap` are leaf components; `Border`, `Button`, and `Shape` are filters; and `VBox` is the only component in the form that is a split.

The second way to categorize the components is by their function:

- Passive visuals establish appearance and spacing. Examples include `Text`, `Glue`, and `Border`.
- Basic interactors contain an editable value that both the user and the application can read and modify. Examples include `TypeIn`, `Numeric`, and `FileBrowser`.
- Interactive modifiers add behavior to a child. The prototypical example is a `Button`. Most interactive modifiers also add some type of visual feedback. For example, a `Button` adds a ``shadow'' around its child to make the child appear 3-dimensional. Some modifiers, like a `Boolean`, also involve an editable value.
- Helpers are components that control other components in some way. For example, a `PopButton` is a button that causes a subwindow (`ZChassis` or `ZChild`) to appear. A `DirMenu` is a pull-down menu that is used with a `FileBrowser`. The items in the menu are the ancestors of the directory currently being displayed.
- Groupers declare that all their descendants belong to one group for some particular purpose. A `Radio` unites a group of radio buttons, which are `Choice` components.
- Geometers take an arbitrary number of children and lay them out in some way. Examples include `VBox`, `HPackSplit`, and `TSplit`. An `HPackSplit` formats its children like words in an unjustified paragraph. A `TSplit` is a temporal split---at any time, exactly one of its children is visible.

## Properties

Properties provide information that modifies the appearance or behavior of a component. A property subexpression has the following format:

        (keyword value)

The keyword implies the expected type of the value; values are type-checked when the description is parsed by FormsVBT. Nearly all properties have default values and can be omitted. If you are developing a form using the `formsedit` interface-builder, then type- and syntax-errors will be reported and highlighted each time that you issue the ``Do It'' command. If an application gives the FormsVBT runtime system a syntactically incorrect S-expression to parse, FormsVBT will raise an exception to signal the syntax error. For example, the expression

        (Boolean (CheckMark TRUE) (MenuStyle TRUE) "Gravity")

defines a Boolean interactor with two properties. The `CheckMark` property says to use a check mark rather than a check box for visual feedback, and the `MenuStyle` property says that the Boolean should be responsive to a mouse rolling into it, rather than responding only to a mouse click. You would use `MenuStyle` when the Boolean is an element of a menu.

A value must have one of the following types:

Text
  A quoted string.

        (Border (Pattern "NWDiagonals") ...)

Cardinal
  A positive integer.

        (TSplit (Value 4) ...)

Integer
  An integer.

        (Numeric (Min -100) (Max 100))

Real
  A real number. A whole number does not need a decimal point, and a number between -1 and 1 does not need a leading zero.

        (Border (Pen 4.25) ...)

Boolean
  The token `TRUE` or `FALSE`.

        (Boolean (MenuStyle TRUE) ...)

CardinalList
  A list of positive integers.

        (MultiBrowser (Value 1 5 3 19))

TextList
  A list of quoted strings.

        (FileBrowser (Suffixes "i3" "m3"))

Symbol
  A name. For example, the `For` and `Name` properties are of this type:

        (PageButton (For letters) "Next")
        (Button (Name no) "Cancel")

  Names are either identifiers (a letter followed by any number of letters, digits, or underscores), or non-empty sequences of characters from the set

      	! # $ % & * + - . / : < = > ? @ [ ] ^ _ { } ~

  or a sequence of characters and escape sequences surrounded by vertical bars (e.g., `|Sue's button|`). The escape sequences are

      	\n \t \r \f \\ \|

  and `\` followed by three octal digits.

Font
  The name of a font conforming to the specifications in ``X Logical Font Descriptions'' [XWindowSystem] . The font can be specified in two ways: A quoted string in the form that `xlsfonts` prints and accepts as a pattern (we call this the string format), or a list of parenthesized keyword pairs for the parts of a font (we call this the list format). Consider the following example:

        (VBox
          (Text (LabelFont "helvetica_bold14")
              "Helvetica Bold @ 14pts")
          (Text (LabelFont "-*-courier-medium-*-140-*")
              "Courier @ 14pt")
          (HBox (LabelFont (Family "Times")
                           (PointSize 140))
            (Text "Times@14pt")
            (Text (LabelFont Reset
                             (Family "*")
                             (Width "semicondensed"))
               "SemiCondensed@any")
            (Text (LabelFont (PointSize 180)
                             (Slant "i"))
                "Italics@14pt"))))

  The font specification for the top two children of the VBox use the string format. The other font specifications are in the list format. Here's what the example looks like:

  In the list format, the keywords for the parts of a font are

  Foundry | Family | WeightName | Slant
  Width | PointSize | HRes | VRes
  Spacing | AvgWidth | Registry | Encoding

  `PointSize`, `HRes`, `VRes`, and `AvgWidth` take cardinal values or the string `"*"`. All the others take strings. Unspecified parts of a font take on the value of the nearest ancestor component for which the part was specified using the list format. However, the keyword `Reset` causes all unspecified parts of a font to take on the default values assigned by FormsVBT.
Color
  The description of a color either as a triplet of real numbers between 0.0 and 1.0 representing RGB or HSV values, or as a string. The following example shows both formats:

        (Pixmap
          (BgColor .5 0.23 1.0)
          (Color "VeryPaleRed") "MailBox")

  The triplet may be preceded by one of the symbols `RGB` or `HSV`. The default is `RGB`. The symbol `HSV` represents hue-saturation-value. Example:

        (BgColor HSV 0.1 0.45 0.222)

  Appendix [ap:colornames] describes the conventions used for naming colors.

Sx
  An S-expression in the FormsVBT language. For example, the `Title` property of a `ZChassis` (a frame for a subwindow) has this type:

        (ZSplit
          (ZBackground ...)
          (ZChassis
            (Title
              (HBox
                Fill
                "Window # "
                (Border (Text %wid =""))
                Fill))
            ...))

Enumeration
  A set of mutually exclusive tokens. FormsVBT supports the following enumerations:
  Alignment
    Center, LeftAlign, RightAlign}
  Axis
    Horizontal, Vertical
  FeedbackStyle
    CheckBox, CheckMark, Inverting
  Reactivity
    Active, Passive, Dormant, Vanish
  ScrollStyle
    HorOnly, VerOnly, NoScroll, AlaViewport, Auto
  ShadowStyle
    Flat, Raised, Lowered, Ridged, Chiseled
  Think of each enumeration as a collection of Boolean properties, at most one of which may be specified as `TRUE`. If no choices are specified, then it's as if the default choice was given. Here are some examples:

      (Viewport (VerOnly TRUE) (Horizontal TRUE) ...)
      (Filter (Dormant TRUE) (Vanish FALSE)
          (Button ...))
      (Frame (Raised TRUE)
          (Rim (Frame (Lowered TRUE) ...)))

Size
  The description of the dimensions of a component along some axis. It has the syntax

          [size] [+ stretch] [- shrink]

  where size, stretch, and shrink are specified as points in real numbers. Stretch and shrink, if both specified, may be in either order. Spaces are required around the plus and minus signs. The keyword `Inf` is used to indicate a very large value for stretch. See Section [sec:language-sizespec] for more details.

At
  The location of a subwindow component relative to its parent. There are two ways to specify this location: you can say where the center or a particular corner should be positioned; or you can specify where the four edges should appear. To position a subwindow by its center or corner, you write

      (At h v [Center | NW | NE | SE | SW] [Scaled | Absolute])

  If you don't specify the center or a corner, the default is `Center`. If you don't specify whether `h` and `v` are scaled or absolute, the default for this form is `Scaled`, which means that `h` and `v` indicate the proportionate placement in the horizontal and vertical directions of the center or corner; in this case, `h` and `v` must be numbers in the range 0--1. Otherwise, in the absolute case, `h` and `v` represent the horizontal and vertical distance, in points, between the subwindow's center or corner, and the parent window's northwest corner.

  To position a subwindow by its edges, you write

      (At west east north south [Absolute | Scaled])

  The default in this case is `Absolute`, not `Scaled`; it indicates the distance in points between the subwindow's edges and the parent's west and north edges. Note that this is the only case in which you can specify the subwindow's exact size.

  `Scaled` indicates the proportion of the parent window's width and height that mark the subwindow's boundaries. For example,

      (At .10 .10 .90 .90 Scaled)

  is effectively a ``10% Rim'' around the subwindow, while

      (At .50 .50 1 1 Scaled)

  places the subwindow in the parent window's southeast quadrant. See Section [sec:language-atspec] for more details.

### Varieties of Properties

Properties come in three varieties: class-specific, inherited, and universal.

#### Class-Specific Properties

Class-specific properties are defined in conjunction with a specific component class, and are allowed only on components of that class. It is fine for several components to use the same specific property.

There are two very common class-specific properties: `Main` and `Value`.

`Main`
  Many passive leaf components exist to display some object; such an object is specified by a property called `Main`, whose type varies. If this property exists, it is usually required. Its value is usually specified by a shorthand: it simply follows the component keyword, without the word `Main` or parentheses. Here are two examples, in the abbreviated format:

          (Texture "Gray")
          (Pixmap "OpenRightArrow")

`Value`
  The `Value` property specifies the initial state of some user-modifiable value. The type of this property depends upon the value type of the interactor. No class has both a `Main` property and a `Value` property. Here are two examples, in the abbreviated format:

          (Numeric =5)
          (TextBrowser (From "choices.txt") =(2 5 1))

Other specific properties (and there are many) are described with their component classes in Appendix [ap:longcatalog] .

#### Universal Properties

Universal properties are applicable to components of all classes, and have a system-defined meaning. There is currently only one such property: `Name`.

`Name` (type: Symbol; default: none)
  The name of a component, for access by the application. The type of the `Name` property is a Symbol and it has no default value. A form may not contain duplicate names; not all components need to have a `Name` property. The property may be abbreviated: `(Name goButton)` can be written as `%goButton`.

#### Inherited Properties

Inherited properties, like universal properties, may be specified for any component, though they are not relevant to all classes. But they have the special feature that a value specified for one component becomes the default value for all descendants of that component. Thus an inheritable property specification applies not to one VBT, but to an entire subtree. The inherited properties are: `Font` and `LabelFont`; `Color` and `BgColor`; `LightShadow`, `DarkShadow`, and `ShadowSize`. In essence, the inherited properties determine the overall ``look and feel'' of the user interface.

`Font` (type: Font; default: see below)
  The font for components that display selectable text, such as `TextEdit` and the type-in part of a `Numeric`. The type of the `Font` property is Font, and the default value would be written in list format as follows:

        (Font
          (Foundry "*")
          (Family "fixed")
          (WeightName "medium")
          (Slant "r")
          (Width "normal")
          (PointSize 120)
          (HRes "*")
          (VRes "*")
          (Spacing "*")
          (AvgWidth "*")
          (Registry "iso8859")
          (Encoding "1"))

  Essentially, it's a 12-point, fixed-width font that can be scaled (using the `Scale` component).

`LabelFont` (type: Font; default: see below)
  The font for components that display non-selectable text, such as `Text`, and various browsers such as `MultiBrowser` and `FileBrowser`. The type of the `LabelFont` property is Font, and the default value would be written in list format as follows:

        (LabelFont
          (Foundry "*")
          (Family "helvetica")
          (WeightName "bold")
          (Slant "r")
          (Width "*")
          (PointSize 120)
          (HRes "*")
          (VRes "*")
          (Spacing "*")
          (AvgWidth "*")
          (Registry "iso8859")
          (Encoding "1"))

  Essentially, it's a 12-point, boldface helvetica font that can be scaled (using the `Scale` component).

`Color` (type: Color; default: `0 0 0`)
  The foreground color; used for displaying text, bars, borders, the ``on'' pixels of pixmaps and textures, and so on. The default foreground color is black.
`BgColor` (type: Color; default: `.8 .8 .8`)
  The background color; used for displaying text background, glue, and the ``off'' pixels of textures. The default background color is a light gray.
`LightShadow` (type: Color; default: `1 1 1`)
  The color used for the ``light shadow'' in implementing a Motif-like 3-d look. The default light shadow is white.
`DarkShadow` (type: Color; default: `.333 .333 .333`).
  The color used for the ``dark shadow'' in implementing a Motif-like 3-d look. The default dark shadow is a dark gray.
`ShadowSize` (type: Real; default: `1.5`).
  The absolute value of this property is the size of the ``shadow'' in implementing a Motif-like 3-d looks. The default value is 1.5 points.

#### Look and Feel

In order to have an effective Motif-like look and feel, you need to change the `LightShadow` and `DarkShadow` whenever you change the `BgColor`. Shiz Kobara [kobara] provides an excellent set of guidelines for choosing harmonious color triples.

On a grayscale monitor, objects are displayed using the intensity of their color.

On a monochrome monitor, FormsVBT does not support a Motif-like look and feel. Rather, the user interface appears ``Macintosh-like.'' For example, feedback on buttons is given by inverting the image of an object rather than raising and lowering the object; a Radio button uses bitmaps showing a filled or empty circle rather than a 3-d diamond that is either raised or recessed. Behind the scenes, two things are happening. First, on monochrome displays, `BgColor` displays as background and the other colors display in foreground. Second, the FormsVBT interactors are implemented in such a way as to give feedback using a 2-d style when displaying on a monochrome dispay.

Actually, the FormsVBT interactors use the Motif-like style only when they are on a non-monochrome display and the `ShadowSize` property is positive. Therefore, you can force a non 3-d look for a color or gray-scale monitor by setting the `ShadowSize` to be 0. You should probably also change the `BgColor` to be white in this case. Alternatively, you may find it convenient to set `ShadowSize` to be a negative number and the shadow colors to be black, as follows:

      (BgColor "White")
      (LightShadow "Black")
      (DarkShadow "Black")
      (ShadowSize -1.5)

This setup will cause the shadows on various objects, like buttons, to appear as black borders.

## Syntactic Shortcuts

This section describes various shortcuts that make FormsVBT descriptions more readable.

1. The `Main` property may be given simply by giving its value, without the keyword or parentheses. This is allowed only for leaf components.

   > `(Texture (Main "LightGray"))` is same as `(Texture "LightGray")`

2. The `Value` property may be abbreviated by an equal sign, without parentheses, and with no intervening space.

   > `(Numeric (Value 27))` is same as `(Numeric =27)`

   Exception: If it's a TextList or CardinalList, then parentheses are needed.

   > `(MultiBrowser (Value 4 9 2))` is same as `(MultiBrowser =(4 9 2))`

3. The `Name` property may be abbreviated by a percent sign.

   > `(Button (Name xyz) ...)` is same as `(Button %xyz ...)`

4. Any Boolean-valued property may be set true simply by giving its name, without parentheses. By convention, the default value of all Boolean properties is false.

   > `(TypeIn (Scrollable TRUE))` is same as `(TypeIn Scrollable)`

   An element of an enumeration is a Boolean.

   > `(Viewport (Auto TRUE) ...)` is same as `(Viewport Auto ...)`

5. A component of class `Text` may be given simply as a quoted string, provided that no properties other than the string are specified.

   > `(Text "Hello")` is same as `"Hello"`

6. Any leaf component from the following list

   > `Bar Chisel Fill Glue Ridge`

   may be given by its keyword, without parentheses.

   > `(HBox "A Heading" (Fill))` is same as `(HBox "A Heading" Fill)`

## Macros

The FormsVBT language supports macros. A macro is a procedure that returns an S-expression, called the expansion, that replaces the macro call; that is, the expansion is itself a FormsVBT expression. The parameters passed to the macro are not evaluated by the call, although they may be evaluated in the body of the macro. A macro definition can appear anywhere a component or property can appear.

A macro-definition has the following syntax:

`(Macro name [BOA] (formal ... formal) expression)`

A formal parameter is either a name or a list of the form

`(name default)`

where default is any S-expression, the default value for the parameter.

A macro uses either positional binding or keyword binding, but not both. If the definition includes the keyword `BOA` (``By Order of Arguments''), then the macro uses positional binding, and the macro-call must have the form

`(name actual ... actual)`

The actuals are bound to the formals in left-to-right order.

If the definition does not include the keyword `BOA`, then the macro uses keyword binding, and the macro-call must have the form

`(name (formal actual) ... (formal actual))`

The actuals are bound to the formal parameters with corresponding names.

The number of actual parameters may not exceed the number of formal parameters. If there are fewer actuals than formals, then all the remaining formals must have default values.

The body of the macro-definition is an expression that is evaluated (expanded) when the macro is called. Typically, the body is a quoted or backquoted S-expression. As in Common Lisp macros, quoted S-expressions are constants; they expand into themselves. Backquoted expressions are templates; all of the subexpressions are treated as constants except for expressions preceded by a comma or a comma-atsign combination. In the expression ``(A ,x B)`, the value of `x` is substituted as the second element of the list; the expanded list will always have length 3. In the expression ``(A ,@x B)`, the value of `x` must be a list, and the elements of that list are ``spliced in'' between `A` and `B`; the expanded list will have length 2 (if the value of `x` is the empty list) or more. For example, here is a macro that puts a 2-point border around its argument, after surrounding the argument by 16 points of background space on all four sides:

        (Macro Boxed (x)
          `(Border (Pen 2) (Rim (Pen 16) ,x)))

The call `(Boxed (x (Text (BgColor "Red") "Warning")))` expands to

        (Border (Pen 2)
          (Rim (Pen 16)
            (Text (BgColor "Red") "Warning"))))

If the definition of `Boxed` had included the keyword `BOA` then the expression could have been written as

    (Boxed (Text (BgColor "Red") "Warning"))

Thus, for all practical purposes, we've effectively added a new filter-component called `Boxed` to the FormsVBT language.

Here is an example showing the use of default values:

        (Macro Ht BOA (v (n 16)) `(Shape (Height ,n) ,v))

With this definition, the call `(Ht (Button "Go!") 20)`

expands into

        (Shape (Height 20) (Button "Go!"))

The call `(Ht (Button "Stop"))`

uses the default value of `n` and expands into

        (Shape (Height 16) (Button "Stop"))

An example using comma-atsign:

        (Macro V (items)
          `(VBox (Color "Red") Fill ,@items Fill))

Given this definition, the call `(V (items ("abc" "def" "hij")))` expands into

        (VBox (Color "Red") Fill "abc" "def" "ghi" Fill)

Macros must be defined before they are called. The effect of using a macro to redefine an existing name (e.g., `VBox`) is undefined.

It is permitted for a macro to expand into another `Macro`-expression, or into an expression containing another `Macro`-expression. Nested backquotes are permitted; they follow Common Lisp evaluation-semantics.

The expressions that are permitted in the body of a macro are not restricted to quoted and backquoted expressions. As we have already seen, an expression may be the name of a formal parameter; the value of such an expression is the value of the corresponding actual parameter. Other expressions that are permitted include the following:

`(Cat x y z ... )`
  There must be at least two arguments, and all of them must have type `TEXT`. The result has type `TEXT`. Example: `(Cat "Gate-" x "-button")`
`(Empty x)`
  The argument must be a `TEXT`; the result has type `BOOLEAN`.
`(Equal x y)`
  The arguments may have any type; the result has type `BOOLEAN`.
`(Length x)`
  The argument must be a `TEXT` or a list; the result has type `INTEGER`. (FormsVBT does not support a separate type for cardinals.)
`(Sub s start count)`
  The argument s must be a `TEXT`; start and count must be non-negative integers. The result is a `TEXT`.
`(SymbolName x)`
  The argument must be a symbol; the result is a `TEXT`.
`(Intern x)`
  The argument must be a `TEXT`; the result is a symbol.
`(Cons x y)`
  The first argument may have any type. (All S-expressions are REFs.) The second argument must be a list. The result is a list.
`(List x y z ...)`
  The arguments may have any type; the result is a list.
`(`List*` x y ... z)`
  There must be at least two arguments. The last argument must be a list; the others may have any type, and they are ``consed'' onto the front of the last argument. Example: `(List* 1 2 3 '(a b))` is same as `(1 2 3 a b)`
`(Append x y z ...)`
  All the arguments must be lists; the result is a list.
`(Nth x n)`
  The first argument must be a list; the second argument must be an integer in the range [0 .. RefList.Length(x) - 1]. The result is the nth element of the list.
`(NthTail x n)`
  The first argument must be a list; the second argument must be an integer in the range [0 .. RefList.Length(x) - 1]. The result is the nth tail of the list.
`(IF pred x y)`
  The value of the first argument must be a `BOOLEAN`. If the value is `TRUE`, then x is evaluated, and its value is the value of this expression. Otherwise, y is evaluated, and its value is the value of this expression. I.e., this is `IF` as in Lisp, not as in Modula-3.
`(AND x y z ...)`
  All the arguments must be of type `BOOLEAN`, as is the result. The arguments are evaluated from left to right. If any argument evaluates to `FALSE`, the value of this expression is `FALSE`, and the remaining arguments are not evaluated. If all the arguments evaluate to `TRUE`, or if there are no arguments, then the value of this expression is `TRUE`.
`(OR x y z ...)`
  All the arguments must be of type `BOOLEAN`, as is the result. The arguments are evaluated from left to right. If any argument evaluates to `TRUE`, the value of this expression is `TRUE`, and the remaining arguments are not evaluated. If all the arguments evaluate to `FALSE`, or if there are no arguments, then the value of this expression is `FALSE`.
`(NOT x)`
  The argument must be a `BOOLEAN`, as is the result.
`(= x y z ...)`
  There must be at least two arguments. If x is a number (integer or real), then all the other arguments must be numbers of the same type as x, and the result is `TRUE` if they are all equal, and `FALSE` otherwise. If x is not a number, then the result is `TRUE` if all the arguments are the same REF.
`(< x y z ...)` `(<= x y z ...)` `(> x y z ...)` `(>= x y z ...)`
  There must be at least two arguments, and they must all be numbers of the same type as x. The result is of type `BOOLEAN`.

  `(< x y z ...)` is same as `(AND (< x y) (< y z) ...)`

  Likewise for the other operations.

`NIL`
  This is a constant.

Macros provide one kind of extensibility to the FormsVBT language. Another kind of extensibility is provided by the `realize` method for a `FormsVBT.T` object. The `realize` method allows the programmer to define subtypes of the `VBT` classes that FormsVBT uses, such as the `FVTypes.FVButton`. However, it is not currently possible for the client to extend the language with any other `VBT` classes, such as `TranslateVBT.T` or a client-defined subtype of `VBT.Leaf`. See Section [realize] for details.

## Layout

Every component has a natural size in the horizontal and vertical axes; these are its width and height. It may also have shrinkability and stretchability in each axis, to allow it to adapt in a visually pleasing way as the window is resized. The minimum size of a child in each axis is its natural size minus its shrinkability, and the maximum size in each axis is its natural size plus its stretchability. The size range of a component in each axis is the interval between its minimum and its maximum.

The size ranges in each axis are computed for a top-level window by a bottom-up process. Each split computes its ranges as a function of the size ranges of its children; the function used depends on the type of the split.

FormsVBT uses TeX's ``boxes-and-glue'' layout model. At the center of the layout strategy are two split classes, `HBox` and `VBox`. These organize the layout of their children along the horizontal and vertical axes, respectively. To keep the discussion simple, we will explain the algorithm for `HBox`.

An `HBox` reports its size as follows. An `HBox`'s natural width is the sum of the natural widths of its children; its width shrinkability is the sum of the width shrinkabilities of its children (but no more than its natural size), and its width stretchability is the sum of the width stretchabilities of its children. An `HBox`'s height range is the intersection of the height ranges of its children (if the intersection is empty, the children's maximum heights are increased until the intersection is non-empty). The `HBox`'s natural height is the maximum of the natural heights of its children, projected into the range.

Ultimately, the shape of each top-level window is controlled by the user through a window manager. The window manager allows the user to shrink and grow a top-level window in each axis. However, the window manager will not let user grow a top-level window beyond its maximum size bounds, or shrink a top-level window below its minumum size bounds, in each axis. When a top-level window's size is changed, the new size-information is propagated down through the top-level window's tree of subwindows. How each split component communicates this information to its children depends on the type of the component.

When an `HBox` is given some screen real estate to allocate among its children, here's what happens. In the vertical dimension, it gives each child the same vertical height it has been given; that's easy. In the horizontal dimension, things are more interesting. The `HBox` computes the sum of the natural widths of the children; this is the natural width of the `HBox`. Ideally, the `HBox` would give each child its natural width and that's all there is to it. If this is not possible, then either the `HBox` has extra space it must divide among the children, or the `HBox` must take away space from its children.

In the first case, the `HBox` allocates its extra space in proportion to the children's stretchabilities. For example, if the first child has twice as much stretchability as the middle child, and three times as much as the third and last child, then the extra space is divided 6/11, 3/11, and 2/11 to the children, from left to right. In the second case, the `HBox` takes away space from the children in proportion to the amount that each child can shrink.

If the sum of the minimum sizes of the children is greater than the size of the `HBox`, then the `HBox` is said to be overfull. In this case the children are considered in order and given their minimum sizes, as long as there is room. The first child that doesn't fit is given all the space that's left, and the remaining children are given size zero.

If the sum of the maximum sizes of the children is less than the size of the parent, the split is said to be underfull. This produces a state in which the children are stretched larger than their maximum sizes, but in proportion to their relative stretchabilities.

### How Sizes are Specified

Most of the time, sizes are not given explicitly; natural sizes are allowed to take effect. Leaf components have an inherent natural size that is usually data-dependent. For example, the size of a `Text` is the size of the rectangle needed to display it in the appropriate font. In each axis, it has no shrinkability but ``infinite'' stretchability. A vertical `Scroller` has a fixed width (a natural size with no stretch and no shrink). Its natural vertical size is quite small (enough to show a ``thumb''), it has no vertical shrinkability, and it has infinite vertical stretchability. In practice, a vertical scrollbar is an element of an `HBox`, so it takes on the size of the other elements of the `HBox`.

A filter component derives its size information from its child. A `Border` component, for example, takes the size of its child, but adds twice the border's thickness in both dimensions. A `Guard` takes on precisely the size of its child. Appendix [ap:longcatalog] describes how each component computes its shape.

A property of type Size is used to describe the size of a component along one dimension. It has the syntax

        [size] [+ stretch] [- shrink]

where size, stretch, and shrink are specified as points in real numbers. Stretch and shrink, if both specified, may be in either order. Spaces are required around the plus and minus signs. The keyword `Inf` is used to indicate a very large value for stretch; it may also be spelled `inf` or `INF`.

A natural size may be overridden, completely or in part, by specifying the `Width` and `Height` properties on a `Shape` filter. For the sake of simplicity, let's consider just the `Width` property. There are eight situations to consider: when size, stretch, and shrink are all missing; when just size is given; when just stretch and shrink appear; and so on.

See Table [flexvbt] for details.

This table describes what `Shape` reports, as a function of its child's size. The notation `<q-p, q, q+r>` refers to the child's size: the natural size is `q`; it has `p` shrinkability, so it can shrink to a minimum of `q-p`, and it can stretch to a maximum of `q+r`.
all missing | `<q-p, q, q+r>` A no-op; reports the child's size
`size` | `<size, size, size>` Constrains child's natural size to `size`, with no stretch or shrink
`- shrink` | `^lt;q-shrink, q, q+r>` Forces child's shrink to be `shrink`; doesn't change child's natural size or stretchability
`+ stretch` | `<q-p, q, q+stretch>` Forces child's stretch to be `stretch`; doesn't change child's natural size or shrinkability
`- shrink + stretch` | `<q-shrink, q, q+stretch>` Changes child's shrink to be `shrink` and its stretch to be `stretch`; doesn't change child's natural size
`size - shrink` | `<size-shrink, size, size>` Changes child's size to be `size` with no stretchability and with `shrink` shrinkability
`size + stretch` | `<size, size, size+stretch>` Changes child's size to be `size` with no shrinkability and with `stretch` stretchability
`size - shrink + stretch` | `<size-shrink, size, size+stretch>` Changes child's size to be `size` with `shrink` shrinkability and with `stretch` stretchability

A few common paradigms merit mention. First, to remove whatever inherent stretchability a component has, use

        (Shape (Width + 0) ...)

Second, to make a component stretchy regardless of its inherent stretchiness, use

        (Shape (Width + Inf) ...)

And third, to set a component to a particular size, e.g, 100, use:

        (Shape (Width 100) ...)

### Precedence of Size Constraints

The various constraints on the size of an object sometimes come into conflict. They take precedence as follows:

1. Downward-propagating constraints: window size forced by Trestle, vertical size forced by an `HBox`, and so on.
2. Explicit size information, given by a `Shape` filter.
3. Upward-propagating natural size information: inherent size of leaves, filters taking size from their children, an `HBox` taking width from the sum of its children's widths, on so on.

## Subwindows

In addition to organizing child components by grouping them horizontally or vertically, FormsVBT allows child components to overlap. The split that does this organization is called a `ZSplit`.

There are two very different ways to use a `ZSplit`.

1. If you don't like arranging elements in horizontal and vertical boxes, you could place each element at a specific location. Many UI Builders follow this model; it has its advantages and disadvantages. We rarely use this style at SRC.
2. You can use `ZSplit`s as a container for overlapping, often transient subwindows that are not installed as top-level windows.

Without loss of generality, we'll talk just about the second style of use.

A `ZSplit` is written like this:

    (ZSplit
          The first child:
      (ZBackground ...)
          Any number of other z-children:
      (ZChild ...)
      (ZChassis ...)
      ...
      )

The first child is called the background. It is displayed below all other children.

The other children are ordered from bottom to top in the z-dimension. A non-background child of a `ZSplit` should be a `ZChild` or a `ZChassis`. It has an `Open` property to say if it should be initially visible (``mapped'') or invisible (``unmapped'').

It also has an `At` property to control where it should appear when it is made visible. The syntax of the `At` property is described below.

A `PopButton` is a button that causes a named subwindow to appear. A `PopMButton` is a version of `PopButton` that is appropriate for inclusion in a menu.

A `CloseButton` is a button that causes a named subwindow to disappear.

A `ZGrow` is a button that is used to change the size of a subwindow. A `ZMove`-component is used to change a subwindow's position by dragging.

A `ZChassis` is just a `ZChild` that has a standard configuration, including a frame whose banner includes a `CloseButton`, a title inside a `ZMove`, and a `ZGrow`.

#### The ``At'' Property

The location of a subwindow (denoted by a `ZChild` and `ZChassis` component) is specified using a property named `At`. The `At` property is a list that can take one of two forms: the ``corner'' form (two numbers, an optional corner, and an optional coordinate type); or the ``edges'' form (four numbers and an optional coordinate type). The coordinate types are either `Absolute`, which means that the coordinates represent the distance in points from the background window's northwest corner, or `Scaled`, which means that the coordinates represent a fraction (a number in the range 0--1) of the background window's width or height. Here are the two forms of the `At` property: `(At h v [Center | NW | SW | NE | SE] [Scaled | Absolute] ) (At west east north south [Absolute | Scaled] )`

If the list contains two numbers, then these coordinates specify the center of the subwindow. If the list contains two numbers and a corner, then these coordinates specify the position of that corner of the subwindow. In either case the default coordinate type is `Scaled`.

For example, `(At 0.5 0.5)` means that the center of the subwindow should be placed halfway across and halfway down the background window, i.e., that it should be centered in the background window. (If there is no `At` property, this is the default.)

`(At 0.2 0.3 NW)` means that the northwest corner of the subwinbdow should be place 20% of the way across the background window, and 30% down. This can also be written as `(At 0.2 0.3 NW Scaled)`. Scaled coordinates must be written as numbers (integers or reals) in the range 0--1.

`(At 100 237.5 Absolute)` means that the center of the subwindow should be placed 100 points east and 237.5 points south of the background window's northwest corner.

`(At 100 237.5 SE Absolute)` means that the subwindow's southeast corner should be placed at that position.

Alternatively, you may specify the edges of the subwindow by using a list with four numbers, representing the west, east, north, and south edges, in that order. The numbers may be followed by a coordinate type; the default coordinate type in the 4-number form is `Absolute`, not `Scaled` as it is in the 2-number form.

If the coordinate type is `Absolute`, then the coordinates represent the distance in points from the background window's northwest corner; this is the only form in which you can specify the subwindow's actual size. For example, `(At 20 120 60 300)` means that the subwindow's width should be 100 points wide (120 - 20) and 240 points tall (300 - 60), and that its northwest corner should be 20 points east and 60 points south of the background window's northwest corner.

`(At .10 .90 .30 1 Scaled)` means that the subwindow occupies the middle 80% horizontally (.90 - .10) and the bottom 70% (1 - .30) of the background window.

`(At .5 1 .5 1 Scaled)` would place the subwindow in the southeast quadrant of the background window.

Here are some additional examples:

        (ZChassis %A (At .2 .3 NW) ...)
        (ZChassis %B (At 130 200 SE) ...)
        (ZChassis %C (At .1 .6 .2 1) ...)
        (ZChassis %D (At 20 120 60 300)

If the `ZSplit` containing the subwindow is 200 points wide and 300 points high, here is what each specification means:

- Subwindow `A` has its northwest corner at (40, 90). That is, its northwest corner is 40 points to the right of the `ZSplit`'s left edge and 90 points below the top.
- Subwindow `B` has its southeast corner at (130, 200).
- Subwindows `C` and `D` have the same positions: The northwest corner is at (20, 60) and the southeast corner is at (120, 300).

The actual location of a subwindow has two additional restrictions. First, FormsVBT will ensure that the size it gives a subwindow will be within the subwindow's acceptable dimensions: the northwest corner stays fixed, and the southwest corner is adjusted. Second, FormsVBT will not pop up a subwindow with its northwest corner north or west of the visible portion of its parent; it will move the subwindow away from the specified position in order to bring it into view.

## Catalog of Components

This section provides a brief description of current FormsVBT components. Appendix [ap:longcatalog] describes the details of each component.

#### Visual components

These leaf and filter components have no interactive behavior; they are used to provide appearance and positioning control.

`Border`
  displays space, in the foreground color, around its child
`Rim`
  displays space, in the background color, around its child
`Pixmap`
  displays a pixmap, centered
`Text`
  displays a single-line text
`Texture`
  displays a textured rectangle
`Bar`
  a line in the foreground color; child of HBox or VBox
`Glue`
  a piece of background filler; child of HBox or VBox
`Fill`
  an infinitely stretchable background filler; child of HBox or VBox
`Frame`
  draws a 3-d border around its child
`Chisel`
  like Bar, but line appears 3-d, chiseled into background
`Ridge`
  like Bar, but line appears 3-d, raised above background
`Scale`
  enlarges or shrinks child
`Shape`
  constrains shape of child

The following filters respond to mouse activity. They do not report events to the application program.

`Viewport`
  adds scrollbars around a child for panning
`Filter`
  controls reactivity and visibility of child

#### Basic Interactors

These are leaf components that have a user-modifiable value. They should always be named so that the application will have access to the value.

`Numeric`
  an editable integer
`Browser`
  a group of lines of text, of which one may be selected
`MultiBrowser`
  a `Browser` in which multiple lines may be selected
`Generic`
  a placeholder to be taken over by the application
`Scroller`
  a vertical or horizontal scrollbar

#### Text Editing Interactors

These leaf components provide extensive text editing facilities.

`TypeIn`
  an editable-text region, typically single-line
`TextEdit`
  a scrollable text-editing area
`Typescript`
  a `TextEdit` with a reader and writer

#### File Browser Interactors

A `FileBrowser` displays the names of the files in a directory, initially the current working directory. The user can traverse the file system by double-clicking on elements in the browser. There are two related leaf interactors that facilitate traversal.

`FileBrowser`
  the list of filenames
`Helper`
  an area for typing filenames
`DirMenu`
  a pulldown menu containing the names of parent directories

#### Basic Buttons

These filters take a child and add some interactive behavior to it.

`Button`
  generates an event when clicked
`Guard`
  click once to remove and expose underlying component
`TrillButton`
  generates an event while mouse is down

#### Boolean and Radio Buttons

A `Boolean` and `Choice` are types of buttons that also maintain some state. A `Radio` is a ``grouper'': it takes a child and changes neither its appearance nor its behavior. Rather, it specifies that it and all its descendants are members of one ``group'' for some particular purpose.

`Boolean`
  toggles on/off when clicked
`Choice`
  a radio button; selects itself when clicked
`Radio`
  defines a group of Choice components

#### Drag and Drop

These buttons provide a way to implement ``drag-n-drop'' and to get semantic feedback.

`Source`
  a button that is dragged
`Target`
  the thing into which a `Source` is dropped

#### Menus

`Menu`
  a pull-down menu; pulls down when anchor is clicked
`MButton`
  a pull-down menu element; generates an event on up-click

Other buttons that can be put into a menu are `Boolean`, `Choice`, and `PopMButton`.

#### Horizontal and Vertical Splits

Splits take an arbitrary number of children and lay them out in some fashion. These splits implement the TeX-like ``boxes-and-glue'' layout model.

`HBox`
  horizontal layout
`VBox`
  vertical layout
`HTile`
  an `HBox` with user-adjustable divider bars between children
`VTile`
  `VBox` with user-adjustable divider bars between children
`HPackSplit`
  arranges children like words in a paragraph
`VPackSplit`
  arranges children like paragraphs in a multi-column newspaper

The layout algorithm for `HTile` and `VTile` is slightly different than for `HBox` and `VBox` when the size of one of its children changes. In the case of the tiles, the algorithm tries to keep existing children with their same relative sizes, which might have been adjusted by the user from their initial assignments. The `HBox` and `VBox` always re-assign sizes, independent of the current sizes of the children.

#### Subwindows

A `ZSplit` organizes its children as overlapping subwindows. The following components allow the user to control the appearance, location, and size of subwindows.

`CloseButton`
  closes a subwindow
`PopButton`
  pops up a subwindow
`PopMButton`
  a menu item that pops up a subwindow
`ZBackground`
  needed around the background child
`ZChild`
  needed around non-background children `ZGrow`
  a button for resizing a subwindow
`ZMove`
  a button for repositioning a subwindow
`ZChassis`
  a handy combination of `ZChild`, `CloseButton`, `ZMove`, and `ZGrow`

#### Temporal Windows

`TSplit`
  a temporal window that organizes its children so that exactly one child is visible at any given time.
`LinkButton`
  displays a specific child in a `TSplit`.
`PageButton`
  switches children displayed in a `TSplit`.

A common use of a `TSplit` is to make an arbitrary component appear or disappear under user control. The component whose visibility is to be toggled is put into a `TSplit` with one sibling: a component with no size. A `LinkButton` to the component will cause it to appear, and another `LinkButton` to the sibling will effectively cause the component to disappear.