# Tutorial

To use FormsVBT, you need a copy of SRC Modula-3 (Version 3.3 or later) and an X server for your system. If you have these, you may want to compile and run the example programs as you read this chapter.

## Getting Started

The first example program is in the file `Hello.m3`:

    MODULE Hello EXPORTS Main;
    IMPORT FormsVBT, Trestle;
    VAR fv := FormsVBT.NewFromFile("Hello.fv"); BEGIN
      Trestle.Install(fv);
      Trestle.AwaitDelete(fv)
    END Hello.

The program builds a form (sometimes called a ``dialog box'' or a ``user interface'') whose description is contained in a file named `Hello.fv`. It installs the form in a top-level window, and then waits until that window is deleted by the user. The window installed by the program is shown in the left half of Fig. [fig:hello] .

The ``Hello FormsVBT!'' example program. The initial version is on the left; the second version on the right.

The file Hello.fv contains the following S-expression:

    (VBox
      (Text "Hello FormsVBT!")
      (Bar)
      (HBox (Text "Left") (Bar) (Text "Right")))

The top-level component is a `VBox`. A `VBox` takes an arbitrary number of ``children'' (sub-components) and arranges them vertically from top to bottom. This `VBox` has 3 children: `Text`, `Bar`, and `HBox`. A `Text` displays a text string, a `Bar` draws a line orthogonal to the orientation of its parent, and an `HBox` arranges its children horizontally, from left to right. The `HBox` has 3 children, two `Text`s and one `Bar`.

The standard way that you compile and link your programs is to use `m3build`. The `m3makefile` for the ``Hello FormsVBT!'' application is as follows:

    import         (formsvbt)
    implementation (Hello)
    program        (Hello)

Then you can compile and link the `Hello` program by typing the shell-command `m3build -S` in the directory containing the source code.

Actually, most Modula-3 programmers follow the convention of storing all of the source files for an application in a directory called `src`. The `m3build` command, when run from `src`'s parent directory, stores all of its derived files (including the executable) in a subdirectory whose name depends on the platform on which you are running. For example, on DECstations, the derived directory is `DS`; on an Alpha running OSF, the directory is `AOSF`. When you follow this directory structure, you should invoke `m3build` without any arguments.

Here's a slightly fancier version of the interface (shown in the right half of Fig. [fig:hello] ):

    (Rim (Pen 20)
      (Border (Pen 1)
        (Rim (Pen 2)
          (Border (Pen 2)
            (VTile
              (Text "Hello FormsVBT!")
              (HBox
                (LabelFont (PointSize 240))
                (Color "White")
                (Text (BgColor "Pink") "Left")
                (Bar)
                (Text (BgColor "VividBlue") "Right")))))))

The top-level component is a `Rim` whose `Pen` property has a value of 20. A `Rim` must contain exactly one child (a `Border` in this case), and it surrounds its child with some background space. Here, the `Rim` provides 20 points of background space between each edge of the window manager's window frame and the rest of the interface. A `Border` is just like a `Rim`, but draws with the foreground color instead of the background color. We replaced the `VBox` with a `VTile`, and deleted its `Bar` child. A `VTile` is like a `VBox`, but it also automatically inserts a dividing bar between its children; by dragging the dividing bar, the user can control the division of space among the children. In this example, the `HBox` has been given two properties, `Color` and `LabelFont`. These control the foreground color and font used by the `HBox` and all of its descendants. Similarly, the `BgColor` property changes the background color used.

The fancy version of ``Hello FormsVBT!'' is in the file `HelloFancy.fv`. To run the application using this file, either modify the application to use `HelloFancy.fv` or rename the file `HelloFancy.fv` to be `Hello.fv`. Alternatively, you might find it enjoyable to run the FormsVBT interactive UI builder, `formsedit`. Just type the shell-command

        formsedit HelloFancy.fv

Exercise 1 Write the FormsVBT S-expression for T^4, a Trestle Tiling Monster of Order 4. (See the Trestle Tutorial, Fig. 2 on page 5.)

## Resources

A resource is constant data needed by an application program at runtime; often it is ``loaded'' at startup time. Almost all FormsVBT programs have resources, such as the `.fv` (pronounced ``dot ef vee'') files that specify the user interface. Other typical resources specific to an application include bitmaps, cursors, and help-texts.

When an application is built, its resources can be ``bundled'' with the executable image. The primary benefit of this feature is that applications are self-contained with respect to the resources they need. Thus, you can copy an executable to a remote site and you won't need to copy the resource files and install them in the same place as they were when the application was built. Also, your application will be insulated against changes in library resources.

The easiest way to do this is to name the resources and the bundle in the `m3makefile`, as in this example:

    import         (formsvbt)
    resource       (Hello.fv)
    bundle         (HelloBundle)
    implementation (Hello)
    program        (Hello)

The second line declares that there is a resource named `Hello.fv`. The third line has the effect of collecting all the named resources (only one in this case) and creating an interface called `HelloBundle` that provides access to them. The program would then be modified to look like this:

    MODULE Hello EXPORTS Main;
    IMPORT FormsVBT, HelloBundle, Rsrc, Trestle;
    VAR
      path := Rsrc.BuildPath(HelloBundle.Get());
      fv   := NEW (FormsVBT.T).initFromRsrc ("Hello.fv", path);
    BEGIN
      Trestle.Install(fv);
      Trestle.AwaitDelete(fv)
    END Hello.

The call to `HelloBundle.Get` returns a bundle that is used to create a resource-path, which is then searched by the `initFromRsrc` method.

But what if you want the application to use new resource files? For example, you might have changed some details of the `.fv` file that don't require any changes to the application code. Do you have to rebuild the entire application?

Fortunately, the answer is no. However, you do need to tell FormsVBT that you want it to look for those resources in the file system before it looks for them among the resources that were bundled into the application. You do this by changing the resource-path so that it includes one or more directories before the bundle.

The convention is to use environment variables whose names are spelled by combining the program's name with the string `"PATH"`. This variable should be set to a list of directory-names, each separated by a colon. So, if you want to run the `Hello` program using the `Hello.fv` file that's in Smith's home directory instead of the one that's bundled with the application, you would type something like this shell command:

        setenv HelloPATH /user/smith

In the program, you would construct a resource-path that included this directory by adding the name `HelloPATH`, prefixed with a dollar sign:

    MODULE Hello EXPORTS Main;
    IMPORT FormsVBT, HelloBundle, Rsrc, Trestle;
    VAR
      path := Rsrc.BuildPath("$HelloPATH", HelloBundle.Get());
      fv   := NEW (FormsVBT.T).initFromRsrc ("Hello.fv", path);
    BEGIN
      Trestle.Install(fv);
      Trestle.AwaitDelete(fv)
    END Hello.

## The FormsVBT Language

Syntactically, there are three types of components in FormsVBT: leaves, filters, and splits. A leaf has no children; a filter has exactly one child; and a split has any number of children.

The FormsVBT leaf components include passive objects like texts and pixmaps, as well as interactive objects like scrollbars and type-in fields.

A filter modifies its child's looks or behavior in some way. We've seen how a `Border` draws a border around its child. Another common filter is `Boolean`. It adds a check box to the left of its child and makes the box and the child sensitive to mouse clicks. It's important to realize that the child may be any arbitrarily complex arrangement of components, although a `Text` component is the most common.

The purpose of most splits is to divide the display area among its component-children (sub-components). In addition to the horizontal and vertical splits that we've seen, FormsVBT provides a temporal split (`TSplit`) to display exactly one child at any given time, and a z-axis split (`ZSplit`) to display children as overlapping subwindows.

Components are written as lists containing the component's type, followed by some number of properties, followed by some number of sub-components. Properties are written as lists containing a keyword and a value. For example, in the S-expression:

      (HBox
        (LabelFont (PointSize 240))
        (Color "White")
        (Text "Left")
        (Bar)
        (Text "Right")

the parent-component's type is `HBox`. This component has two properties; the first property has the keyword `LabelFont` and the value `(PointSize 240)`; the second has the keyword `Color` and the value `"White"`. It has three sub-components: `(Text "Left")`, `(Bar)`, and `(Text "Right")`.

The value of each property is type-checked when the description is parsed. The possible types include strings, integers, and real numbers, as well as more complicated types like color and font specifications.

So far, we have seen two kinds of properties. Class properties, like `Pen`, are defined in conjunction with specific components, and are allowed only on components of that class. Inherited properties, like `Color` and `LabelFont`, may be specified for any component, though they are not relevant to all component types. The inherited properties have the feature that a value specified for one component becomes the default value for all descendants of that component. Thus an inherited property applies not to one component, but to an entire subtree.

FormsVBT supports a third type of property, universal properties. A universal property can be specified on any component, and its value applies only to that component.