Journal Articles

Object Layout with the SVL Interface Toolkit


D. Labute
Chemical Computing Group Inc.


Introduction

One of the more mundane programming tasks when creating a Graphical User Interface (GUI), is the physical placement of the interface objects (buttons, labels, text fields etc) within the window. Many GUI Builders offer a simple point and click mechanism for placing the objects where the programmer desires. This method is easy, yet inadequate for many reasons including:

  1. Subsequent modifications to the window usually requires manually rearranging many or all other objects in the window.

  2. Windows with dynamic contents (ex: variable number of buttons) are difficult if not impossible to create.

  3. Specific fonts are not available on all systems. A window's appearance can change drastically if its fonts are changed out from under it, usually for the worse if the programmer has not thought to account for it.

  4. Screen sizes and resolutions vary from machine to machine. On some SGI machines, for example, screen resolution is dramatically altered when switching to and from stereo mode. Windows which do not take such factors into account layout poorly and are usually non-functional.

Other GUI Builders offer programmatic or algorithmic layout management. These services are either far too simplistic and confining, or so complicated that the code needed to layout a window encompasses half the program. Furthermore, complicated layout schemes often introduce non-standard and non-intuitive notions which require a level of mastery before becoming proficient. Most Motif programmers share this sentiment. The SVL Interface Toolkit, embedded within the Scientific Vector Language (SVL), provides programmatic layout of interface objects with a small set of intuitive and concise directives. The purpose of this article is to review the SVL Interface Toolkit, embedded within MOE.

SVL Interface Object Layout - The Basics

In SVL, the interface objects created in a window form a hierarchy. That is, a parent object may have one or more child objects, each of which may, in turn, parent one or more child objects of their own, and so on. Each parent object is responsible for laying out its children. For this reason, parent objects are referred to as "manager objects". The simplest type of manager object is a vertical layout manager (i.e. one which stacks its children vertically) as shown below:

This window layout was performed by creating a label, a button, and a text field as children of a vertical layout manager, called a "Vbox". The SVL code to create and display this window is listed below:

    local wkey = WindowCreate [
      Vbox : [
        Checkbox: [ title:'Checkbox:', text:'abc'],
        Button: [ title:'Button:', text:'abc' ],
        Text: [ title:'Text:' ]
      ]
    ];

    WindowShow wkey;
    WindowWait wkey;
    WindowDestroy wkey;

The other manager objects in the SVL Interface Toolkit are the horizontal layout manager, or "Hbox", which stacks its children horizontally, and the matrix layout manager, or "Mbox" which arranges its children in a matrix of specifyable dimensions. For all intents, a Vbox object is an Mbox with one column, while an Hbox object is an Mbox with an infinite number of columns. The Shell, the topmost interface object in the hierarchy of a standalone window, is actually a Vbox, thus child objects of a standalone shell will stack vertically by default. The specification of the Vbox object in the code fragment above is therefore redundant. One can easily imagine the power and flexibility of combining and nesting layout managers, and using creation order to create sophisticated layouts.

Each SVL Interface Toolkit layout manager creates a matrix, or grid, of cells, each containing one child object. The size of an individual cell depends upon the size of all other cells in its row and column. Layout managers have only two tasks to perform. The first is to size the cells of the matrix such that all children are contained within their respective cell. The second is to position the children (within their cells) such that they line up "nicely" with objects in neighboring cells. The latter of the two tasks is where most toolkits fall short. Each object needs a set of hints, or directives to position itself within its cell. Directives such as centering an object, and providing a margin around it are fairly trivial. The directive that is really needed is the "make-my-objects-line-up-so-that-they-look-nice" directive!

The SVL Interface Toolkit layout managers implement this directive implicitly. In fact, most interface specifications will layout "nicely" without any additional hints or directives at all. Objects simply "know" how they like to line up, even when surrounded by margins, extra spacing, and 3D shadows, or when accompanied by titles. Even changes to the textual contents of buttons and labels rarely require any intervention by the programmer to preserve a desired look. The menial task of repeatedly tweaking a window to get things to line up is greatly reduced.

A Rich Set of Directives

Obviously, the layout managers are not psychic. If they were, SVL would just provide the "window-that-I-need-for-my-SVL-program" object. For this reason, the SVL Interface Toolkit provides a small set of concise and intuitive layout directives, specifiable as object attributes. The following attributes are available to all interface objects:

  • margin adds a small margin around the object;
  • shadow adds a 3D shadow around the object;
  • title adds a title to the left of the object;
  • titleTop puts the title on top of the object;
  • flushLeft, flushTop forces the object to the left/top of its cell;
  • centerH, centerV directionally centers an object within its cell;
  • extendH, extendV directionally resizes an object to fit its cell;
  • resizeH, resizeV directionally resizes the object as the window resizes.

For a more detailed list and description of these attributes, please see the SVL manual.

The following attributes are available to layout managers (Vbox, Hbox, Mbox) only:

  • spacingH, spacingV directional spacing between columns/rows of objects;
  • unformRows, uniformCols requests that all rows/columns have equal height/width;
  • columns - number of columns is a matrix layout manager (Mbox).

An important point should be made about the resizeV and resizeH attributes. Unlike other toolkits, the SVL Interface Toolkit was designed to simplify the specification of resizable objects. A typical example would be creating a window containing a Listbox which resizes as the window is resized by the user. Eliciting this behavior in SVL is merely a matter of specifying the resize attributes on the Listbox object - that's it. The toolkit automatically knows to resize the rest of the object hierarchy accordingly.

Interface Layout In Action

The best way to see how interface object layout is trivial in SVL is to see it in action. The window, shown below, is the interface for a calculator. The window is resizable. That is, if the window is resized, the buttons in the calculator will grow/shink to match the window size.

The SVL code to create and layout this window is listed below. Notice how virtually no extra directives and attributes, other than object hierarchy and creation order, are required to specify the layout. The only layout directives and attributes used are extend and resize. These are required to allow the window to respond to resizing, and to extend objects to fit their cell sizes. The rest of the layout is automatic. Recall that the topmost window object in the hierarchy behaves as a Vbox.

    local wkey = WindowCreate [
      Text : [ extendH:1 ],

      Hbox : [
        Radio : [ text:['Deg','Rad','Grad'] ],
        Button : [ text:'AC', background:'red' ],
        Button : [ text:'CE', background:'orange' ]
      ],

      Button : [
        columns: 5, extendH: 1, foreground: 'blue',
        text: [
          '1/x','x^2','sqrt','y^x','x!',
          'sin','cos','tan','ln','log'
        ]
      ],

      Hbox : [
        Button : [
          columns: 1, extendV: 1, foreground: 'brown',
          text: ['INV','MC','MR','M+'],
        ],

        Button : [
          columns: 4, resizeV: 1, resizeH: 1,
          text: [
            '7','8','9','/',
            '4','5','6','*',
            '1','2','3','-',
            '0','.','=','+'
          ]
        ]
      ]
    ];

As with most programmatic layout schemes, achieving an exact look is not always possible, especially when screen and font changes come into play, as described earlier. Instead, an acceptable layout which "looks nice" is generated. A positive side effect of this behavior is that a common style is preserved between application windows, with virtually no effort. As far as flexibility goes, one would be hard pressed to find a layout which is beyond the capabilities of the SVL Interface Toolkit. In fact, the entire MOE interface is written using the exact same layout methods, with just as little effort.



Daniel Labute is the author of much of MOE's graphical user interface and the SVL Interface Toolkit at Chemical Computing Group Inc.