- 33 -

Interviews

by Kamran Husain

IN THIS CHAPTER


In this chapter, you will learn about the Interviews C++ class library development system. You will learn about the tools available for Interviews and how to use them to create front-end GUI applications.

Interviews offers a rich set of C++ functionality and tools for building applications. This chapter can't possibly do it justice in the space provided. By reading to the end of the chapter, though, you will get a feel for creating truly object-oriented applications using Interviews.

To get the most out of this chapter, you need some knowledge of how to run the C++ compiler and how to program in object-oriented languages. If you have not already done so, you should install the X window package with at least Motif window manager (mwm) or the OPEN LOOK manager (olwm).

What Is the Interviews System?

The Interviews subsystem is a windowing system for X Window. Interviews is copyrighted by The Board of Trustees of the Leland Stanford Junior University. Interviews was developed by Mark Linton's group at Stanford.

What makes Interviews an interesting environment is that it provides an object-oriented approach to building user interfaces. All components within Interviews, such as windows, menus, scrollbars, and so on, are objects with inherited behavior. The name Interviews is derived from the package presenting an interactive view of some data. For example, a front end to a database provides an interactive view to the data in the database.

How to Get and Install Interviews

The Interviews kit is distributed in two packages: iv1 and iv2. The first package, iv1, contains the binary and source files for the libraries. The second package includes the man pages and a PostScript reference manual for the Interviews system.

The Interviews package is included on the CD that comes with this book.


TIP: I recommend that you print the PostScript version of the Interviews manual if you plan on developing any applications in Interviews. This manual is in the file /usr/doc/interviews/ refman.PS. You need a PostScript printer to print this document, or you can view this manual via ghostscript.

Sample Applications

The Interviews package comes with several applications found in the /usr/interviews/bin directory. Applications to give you an idea of some of Interviews' potential are shown in the dclock and idemo applications, shown in Figures 33.1 and 33.2.

FIGURE 33.1. The Interviews dclock application.

FIGURE 33.2. A demo application with Interviews.

The list of other ready-to-run applications under Interviews is shown in Listing 33.1.

We will cover some of these applications in a bit more detail in this chapter. The rest you can try out on your own.

Listing 33.1. The binary files for Interviews.

$ ls -al /usr/interviews/bin



total 1187



drwxr-xr-x    2 root     root         1024 Nov  5 17:40 .



drwxr-xr-x    6 root     root         1024 Nov  5 17:40 ..



-rwxr-xr-x   1 root     root         9220 Apr 17  1994 alert



-rwxr-xr-x   1 root     root           82 Apr 17  1994 cpu



-rwxr-xr-x   1 root     root        17412 Apr 17  1994 dclock



-rwxr-xr-x   1 root     root       259076 Apr 17  1994 doc



-rwxr-xr-x   1 root     root         1616 Apr 17  1994 ibmkmf



-rwxr-xr-x   1 root     root       689156 Apr 17  1994 ibuild



-rwxr-xr-x   1 root     root        37892 Apr 17  1994 iclass



-rwxr-xr-x   1 root     root        17412 Apr 17  1994 idemo



-rwxr-xr-x   1 root     root       115716 Apr 17  1994 idraw



-rwxr-xr-x   1 root     root         9220 Apr 17  1994 ifc



-rwxr-xr-x   1 root     root          642 Apr 17  1994 ivmkmf



-rwxr-xr-x   1 root     root        13316 Apr 17  1994 logo



-rwxr-xr-x   1 root     root        17412 Apr 17  1994 mailbox



-rwxr-xr-x   1 root     root         1736 Apr 17  1994 remind




TIP: You can always try the applications in /usr/interviews/bin from an xterm by running the command as a background process. For example, to run the ibuild application, type the command ibuild &. If you do not run ibuild as a background process, you can press Ctrl-z to put it in the background of a bash shell.

idraw

Let's start with an application in the Interviews package. Learning this application will familiarize you with Interviews and working with its development tools. (See Figure 33.3.)

The idraw application lets you draw rectangles, polygons, ellipses, and other shapes interactively. Drawings are stored in files that can be printed on a PostScript printer. You can open an existing drawing by typing a filename on the command line when starting up idraw.

You must engage a tool before you can use it. You engage a tool by clicking on its icon, or by typing the character that is below and to the right of its icon. The icon of the drawing tool that's engaged appears in inverted colors. When it is engaged, you use the tool by clicking the left mouse button in the drawing area.

The Select, Move, Scale, Stretch, Rotate, and Alter tools manipulate existing graphics. Magnify makes a part of the view expand to fill the entire view.

FIGURE 33.3. The idraw application's main screen.

Text, Line, Multiline, Open Spline, Ellipse, Rectangle, Polygon, and Closed Spline create new graphics. Each tool works as follows:


TIP: The middle mouse button invokes Move while the mouse is in the drawing area.

idraws Pull-Down Menus

The pull-down menus File, Edit, Structure, Font, Brush, Pattern, FgColor, BgColor, Align, and View, located above the drawing area, contain commands for editing the drawing and controlling idraw's execution. The File menu contains the following commands to operate on files:

New Destroys the current drawing and replaces it with an unnamed blank drawing.
Revert Rereads the current drawing, destroying any unsaved changes.
Open... Specifies an existing drawing.
Save As Saves the current drawing in a file with a specific name.
Save Saves the current drawing in the file from which it came.
Print... Sends a PostScript version of the drawing to a printer or a file.
Import Graphic... Can import images from files in the following formats: TIFF; PostScript generated by pgmtops, ppmtops, and idraw; X bitmap format; and Unidraw format.
Quit Quits idraw.
The Edit menu contains the following commands for editing graphics:

Undo Successive Undo commands undo previous editing operations.
Redo Successive Redo commands redo subsequent editing operations up to the first operation undone by Undo. Undone operations that have not been redone are lost as soon as a new operation is performed.
Cut, Copy, Paste Removes the selected graphics from the drawing and places them in a temporary storage area. Copy keeps the original on the drawing area. Paste puts the contents of the storage area, if any, into the location selected by the mouse.
Duplicate Duplicates the selected graphics and adds the copies to the drawing.
Delete Destroys all selected graphics.
Select All Selects every graphic in the drawing.
Flip Horizontal,
Flip Vertical
Flips the selected graphics into their mirror images along the horizontal or vertical axis.
90 degrees Clockwise
and CounterCW
Rotate the selected graphics 90 degrees clockwise or
counterclockwise.
Precise Move...,
Precise Scale...,
Precise Rotate...
These buttons let you move, scale, or rotate graphics byexact amounts that you type in a dialog box. You can specify movements in pixels, points, centimeters, or inches. Scalings are specified in terms of magnification factors in the horizontal and vertical dimensions. Rotations are always in degrees.
The Structure menu contains the following commands to modify the structure of the drawing, which is the order in which graphics are drawn:

Group Collects the selected graphics in a newly created picture.
A picture is simply a graphic that contains other graphics. Group enables you to build hierarchies of graphics.
Ungroup Dissolves any selected pictures.
Bring To Front Brings the selected graphics to the front of the drawing so that they are drawn on top of (after) other graphics.
Send To Back Sends the selected graphics to the back of the drawing so that they are drawn behind (before) other graphics.
The Font menu contains a set of fonts in which to display text. When you set the current font from the menu, you also set the font of all selected graphics to that font. A font indicator in the upper-right corner displays the current font.

The Brush menu contains a set of brushes with which to draw lines. When you set the current brush from the menu, you also set the brush of all selected graphics to that brush. The nonexistent brush draws invisible lines and non-outlined graphics.

The arrowhead brushes add arrowheads to one or both ends of lines, multilines, and open splines. A brush indicator in the upper-left corner displays the current brush.

The Pattern menu contains a set of patterns with which to fill graphics, but not text. Text always appears solid, but you can use a different color than black to get a halftoned shade. When you set the current pattern from the menu, you also set the pattern of all the selected graphics to that pattern. The nonexistent pattern draws unfilled graphics, while the other patterns draw graphics filled with a bitmap or a halftoned shade.

The FgColor and BgColor menus contain a set of colors with which to draw graphics and text. When you set the current foreground or background color from the FgColor or BgColor menu, you also set the foreground or background color of all the selected graphics. The ON bits in the bitmaps for dashed lines and fill patterns appear in the foreground color; the OFF bits appear in the background color.

A black-and-white printer prints a halftoned shade of gray for any color other than black or white. The brush, pattern, and font indicators all reflect the current colors.

The Align menu contains commands to align graphics with other graphics.

The first graphic selected stays fixed, while the other graphics move in the order that they were selected according to the type of alignment chosen. The last Align command, Align to Grid, aligns a key point on each selected graphic to the nearest point on idraw's grid.

The View menu contains the following commands:

New View Creates a duplicate idraw window containing a second view of the current drawing. The second view may be panned, zoomed, and edited independently of the first. Any number of additional views may be made in this manner. Changes made to a drawing through one view appear synchronously in all other views of the same drawing. You may also view another drawing in any idraw window via the Open command.
Close View Closes the current idraw window. Closing the last idraw window is equivalent to issuing a Quit command.
Normal Size Sets the magnification to unity so the drawing appears at actual size. A What You See Is What You Get (WYSIWYG) display.
Reduce to Fit Reduces the magnification until the drawing fits entirely within the view.
Center Page Modifies the view over the center of a 8.5- by 11-inch page as it's printed. Other page sizes are not supported to date.
Orientation Toggles the drawing's orientation. If the editor was showing a portrait view of the drawing, it now shows a landscape view of the drawing, and vice versa.
Grid on/off Toggles idraw's grid on or off. When the grid is on, idraw draws a grid of equally spaced points behind the drawing.
Grid Spacing Enables you to change the grid spacing by specifying one or two values in the units desired (pixels, points, centimeters, or inches). If two values are given (separated by a space), the first specifies the horizontal spacing, and the second specifies the vertical spacing. One value specifies equal horizontal and vertical spacing.
Gravity on/off Toggle Toggles gravity on or off. Gravity constrains tool operation to the grid, whether or not the grid is visible.

Changes to Xdefaults

You can customize the number of changes that can be undone and the font, brush, pattern, or color menus by setting resources in your Xdefaults database. Each string of the form idraw.resource:definition sets a resource. For example, to customize any of the paint menus, set a resource given by the concatenation of the menu's name and the entry's number (such as idraw.pattern8) for each entry that you want to override. All menus use the number 1 for the first entry.

You must set resources only for the entries that you want to override, not for all of them. If you want to add entries to the menus, simply set resources for them. However, don't skip any numbers after the end of the menu, because the menu ends at the first undefined resource. To shorten a menu instead of extending it, specify a blank string as the resource for the entry following the last item on the menu. The idraw application understands the resources listed in Table 33.1. Table 33.1. The idraw resources.

history Sets the maximum number of changes that can be undone (20 by default).
initialfont Specifies the font that is active on startup. Supply a number that identifies the font by its position in the Font menu, starting from 1 for the first entry.
font Defines a custom font to use for an entry in the Font menu. Give three strings, separated by whitespace. The first string defines the font's name; the second string defines the corresponding print font; and the third string defines the print size. For example, idraw.font3:8x13bold Courier-Bold 13 defines the third font entry.
initialbrush Specifies the brush that is active on startup. Give a number that identifies the brush by its position in the Brush menu, starting from 1 for the first entry. Define a custom brush to use for an entry in the Brush menu. The definition requires two numbers: a 16-bit hexadecimal number to define the brush's line style (each 1 bit draws a dash and each 0 bit produces a gap) and a decimal integer to define the brush's width in pixels. For example, idraw.brush2:ffff 1 defines a single pixel-wide solid line. If the definition specifies only the string none, it defines the nonexistent brush.
initialpattern Specifies the pattern that is active on startup. Give a number that identifies the pattern by its position in the Pattern menu, starting from 1 for the first entry.
pattern Defines a custom pattern to use for an entry in the Pattern menu. You can specify the pattern from a 16x16 bitmap, an 8x8 bitmap, a 4x4 bitmap, a grayscale number, or the string none. You specify the 16x16 bitmap with sixteen 16-bit hexadecimal numbers, the 8x8 bitmap with eight 8-bit hexadecimal numbers, the 4x4 bitmap with a single 16-bit hexadecimal number, and the grayscale number with a single floating-point number. The floating-point number must contain a period to distinguish itself from the single hexadecimal number, and it must lie between 0.0 and 1.0, with 0.0 corresponding to a solid pattern and 1.0 to a clear pattern. On the printer, the bitmap patterns appear as bitmaps, the grayscale patterns appear as halftoned shades, and the none patterns never obscure any underlying graphics. For example, idraw.pattern8:8421 defines a diagonally hatched pattern.
initialfgcolor Specify the foreground color that is active on startup. Give a number that identifies the color by its position in the FgColor menu, starting from 1 for the first entry, fgcolor. Define a custom color to use for an entry in the FgColor menu. Give a string defining the name of the color, and (optionally) three decimal numbers between 0 and 65,535 following the name to define the red, green, and blue components of the color's intensity. The intensities override the name; that is, idraw looks up the name in a window system database of common colors only if you omit the intensities.
initialbgcolor Specifies the background color that is active on startup. Give a number that identifies the color by its position in the BgColor menu, starting from 1 for the first entry.
bgcolor Defines a custom color to use for the entry in the BgColor menu. The same rules apply to background colors as to foreground colors.

ibuild

The ibuild package is an editor that enables you to graphically create a user interface for an Interviews application. The ibuild application can save your work as an external file, or as actual C++ code that, when compiled, generates the same user interface that you would create with ibuild. You restore a previously saved interface by typing ibuild and the interface filename on the command line. (See Figure 33.4.)

FIGURE 33.4. The ibuild application.

TIP: The idraw and ibuild applications are very similar in terms of the semantics for editing and other viewing commands. If you learn one of these two tools, you will feel at home with the other.

The ibuild application uses the TOOLDIR environment variable for its tools and other parameters. If TOOLDIR is not defined, ibuild looks for its parameters in the current working directory.

Let's examine the layout of the menus.

The first row of an ibuild editor displays information about its brush (border width), foreground and background color, and so on in a fashion similar to that in idraw. The next two rows show tools that initiate direct manipulation and pull-down menus that contain commands. A panner on the top-right corner lets you pan and zoom the workspace.

The middle portion of the editor shows the workspace for composing and assembling user interface components.

The bottom of the editor contains rows of objects in the form of names and iconic drawings that represent familiar Interviews abstractions. Clicking on one tool, dragging, and releasing it in the workspace enables a user to place an instance of the corresponding prototype at the desired location.

Direct manipulation tools lie horizontally along ibuild's second row. You must engage a tool before you can use it. You engage a tool by clicking on its icon, or by typing the character below and to the right of its icon. The icon of the tool that's engaged appears in inverted colors. When it is engaged, you use the tool by clicking the left mouse button in the workspace.

The Select, Move, Resize, Examine, Relate, and Edit tools manipulate text-based user interface components. Magnify makes a part of the view expand to fill the entire view. Narrow enables a user to navigate the structure of a composed interface in the same editor.

The ibuild application provides the following tools:

The Select tool is used for selecting an object and unselecting all others. An object is selected if its handles are visible. Handles are small inverse-video squares that surround the object. If you hold down the Shift key, Select extends the selection. It selects the unselected component (or unselects the selected component) you clicked on, but does not unselect other selections. Clicking anywhere other than on a component unselects everything. You may also drag a rubberband rectangle around a group of components to select all of them simultaneously.


TIP: The right mouse button invokes the Select button while the mouse is in the workspace.

TIP: The middle mouse button invokes the Move button while the mouse is in the workspace.

The Resize tool can change the size of any selected objects. When user interface components from the bottom panel are initially created in the workspace, or when selected components are composed with composition interface objects in the Composition pull-down menu, they are displayed with their natural sizes. Resize simulates the resizing of the application window during running of the application by letting users drag and sweep the selected user interface component.

The Examine tool is used to look at attributes associated with the selected user interface components. User interface components in ibuild contain attributes that assist users in designing the layout of the interface, or in customizing the generated code. Typically, the pop-up menu of the Examine tool shows Info and Props entries as options.

Selecting Info causes a component-specific dialog box to pop up. Some of the common attributes shown in the dialog box include the following: Base Class Name, which describes the actual class name in the Interviews library to which the selected component corresponds; and Class Name, which describes the user-specified class name of the component.

If the value of Class Name is the same as that of the Base Class Name, the library class is used for instantiating the component during code generation, or a set of subclass files are generated to assist the customization of the new class, as described earlier. Member Name describes the member name of the selected component as a member variable of the closest enclosing MonoScene object. If the member name is exported, the MonoScene object can access and manipulate this specific member instance. Canvas Dimensions shows how much workspace (corresponding to actual screen space) in pixels is actually allocated to the selected component. Natural Size, Shrinkability, and Stretchability describe how much workspace the selected component wants to have.

The dialog box associated with the Props entry shows the selected component's instance name and user-defined properties. Property specification takes the form attribute:value.

In order to assist users in locating certain elements with certain member names or instance names, ibuild enables a user to probe these attributes by Shift-left-clicking on these elements when they are composed.

The Info entry has a pull-right menu that has class name, member name pairs in it; the pull-right menu associated with the Props entry has class name, instance name pairs.

Examining a GraphicBlock component causes a third Graphics entry to display in the pop-up menu. Selecting this option causes graphics in the GraphicBlock to be transferred to idraw for further refinement.

Graphics can be transferred back to ibuild by simply saving and quitting idraw. Attributes associated with graphics in ibuild that are not known to idraw, such as member name, are not lost in this process. This option is supported only for backward compatibility. A much better technique is to use the Narrow tool to narrow into GraphicBlocks, which changes ibuild into idraw in the same window.


NOTE: All machine-generated names are guaranteed to be unique in one session of ibuild. This property is lost with user-defined names, and when files generated by different sessions of ibuild are compiled together.

The Relate tool provides a direct manipulation interface to semantically connect compatible components. Typically, the end result of the Relate operation is the sharing of attributes between the related components. For example, relating a scroller to a file browser lets the scroller take the file browser's member name as its scrolling target. Relating two push buttons causes the push buttons to mutually exclude each other when receiving mouse clicks. In this case, the second (destination) push button shares the ButtonState defined by the first (source) push button. Relate is also very useful for semantically connecting Unidraw objects. For instance, an Editor needs to be related to all enclosed Unidraw objects such as CommandControls, PanelControls, and Viewers. In this case, the simplest way to establish the relations is to relate the Editor with the object directly below it in the instance hierarchy, which causes the relations to establish recursively.

The Edit tool manipulates text-based components. Engaging the Edit tool enables users to perform editing on MenuItem, PushButton, RadioButton, CheckBox, Message, stringEditor, PulldownMenu, PullrightMenu, CommandControl, HPanelControl, and VPanelControl components.

The Magnify tool magnifies a portion of the interface specified by sweeping out a rectangular area. The ibuild application magnifies the area to occupy the entire screen, if possible.

The Narrow tool enables a user to navigate the structure of composed interfaces in the same editor. Initially, ibuild starts at global scope. Engaging the Narrow tool and selecting a component causes the hierarchy of the interface to be displayed in a pop-up menu, with the highlighted entry showing the current scope. Selecting a different entry causes the editor to switch to the scope of the selected component. For instance, if a user chooses to narrow into an HBox, cutting or pasting components in the workspace now affects only the HBox.


NOTE: Leaf-level components don't define new scopes. Narrowing into graphics-related components such as GraphicBlocks, CommandControls, PanelControls, and Viewers transforms ibuild into idraw in the same window, in addition to switching the scope level. This feature is extremely useful because specifying structured graphics objects, class names, and member names can all be done within ibuild. Firing up idraw using the Examine tool is still supported for backward compatibility purposes.

The Create Tool creates a prototypical tool of the current interface, and installs it in the bottom tools palette. Users can choose between having the filename, a default icon of the existing interface, or a customized bitmap as the new tool's icon. The newly created tool can then be treated as a library tool for instantiation. This allows domain-specific abstractions to be built and used across sessions of ibuild.

The Tools command enables a user to install tools to, or remove tools from, the bottom tools panel. Users can choose to install (or remove) multiple tools from the left (right) stringbrowser by selecting multiple entries and clicking the << Install (or Remove >>) button.

The Execute tool lets the user choose an executable from a file-chooser, and executes the selected file without leaving ibuild.

The Quit command exits the current session of ibuild.


NOTE: The Edit menu for ibuild contains commands that are very similar to those in idraw. Refer to the idraw section for more details.

CAUTION: Changes made with the Examine tool and Relate tool can be undone.

The Show Glue tool shows HGlue components with horizontal strips and VGlue components with vertical strips. Showing Glue components with strips makes the structure associated with the interface more apparent.

The Hidden Glue tool shows HGlue and VGlue components with their background color. This is useful when the actual appearance of the interface is desired.

The Natural Size tool shows the selected interface components in their natural form, similar to the way they are displayed initially when the generated interfaces are executed.

ibuilds Pull-Down Menus

The pull-down menus File, Edit Composition, Border, FgColor, BgColor, Align, and View lie across the third row. They contain commands that are executed by pulling down the menu and releasing the mouse button on the command, or by typing the character associated with the command.

The File menu contains the following commands to operate on files:

Generating Source Files

The Generate button generates code for the interfaces in ibuild. A sequence of dialog boxes pops up to let users check off files that they don't want to be overwritten. The generated files include sets of subclass files and support files. Subclass files have class name suffixes, and support files have filename postfixes. For instance, the filename of a session of ibuild is dialogBox, and the top-level MonoScene object that drives the interface is DialogBox.

Support files generated include the following:

For each MonoScene component in ibuild, a set of subclass files is generated. In this case, they include the following:

When you regenerate the code for an application, you are asked in a dialog box whether you want to regenerate these files. As a general rule, all the default files that ibuild recommends by checking in their dialog box should be overwritten.

The dialogBox-props file contains Interviews properties for customization. Rewrite this file whenever you regenerate.

The dialogBox-main.c file contains a prototypical main routine to drive the interface. Rewrite this file whenever you regenerate.

The DialogBox-core.c file encapsulates all information about the appearance of the interface. The protected member variables are declared in this file.

The DialogBox-core.h file describes what objects are exported to the subclass objects (such as DialogBox) for manipulation. This file is, and should be, overwritten whenever you regenerate a new application using ibuild.

The DialogBox.h and DialogBox.c files enable users to implement application-specific interfaces. When you are regenerating code from an ibuild session, you are asked whether you want to overwrite these files. If you already have application-dependent code in these files, you don't want to overwrite these files. By default, ibuild doesn't overwrite these files.


NOTE: These two files are under the user's control; the core files (DialogBox-core.[ch]) are under ibuild's control.

The Composition menu contains commands to modify the structure of the interface. See Table 33.2 for a list of these commands.

Table 33.2. Composition commands.
Command Action
Dissolve Dissolves the selected components by deleting the top-level parents and exposing the children of the selected components. Leaf-level components cannot be dissolved. Compose the selected components with the corresponding composition object. The order of selection decides the order in which they are composed.
Hbox Tiles the selected components left to right in abutting fashion.
Vbox Tiles the selected components top to bottom in abutting fashion.
Deck Stacks the selected components on top of each other, with the last selected component on the top.
Frame Puts a frame around each of the selected components.
ShadowFrame Puts a shadow frame around each of the selected components.
ViewPort Puts a viewport around each of the selected components.
MenuBar Tiles the selected components row by row as in an HBox (horizontal box). It also implements the sweeping effect when MenuItems, pull-down menus, or pull-right menus are the selected components.
Shaper Redefines the resizing behavior of the selected components. Shaper is an ibuild-generated class, which is useful for overriding the default resizing behavior of library components.

The Reorder command reorders the components inside a composition according to the current selection order. For instance, narrowing into an HBox, reselecting its components, and executing Narrow defines ordering of the components in the HBox corresponding to the new selection order.

Similarly, the Raise command brings the selected components to the front of the interface so that they are drawn on top of (after) the other components in the interface. For example, if a selected component is raised in a Deck, it appears on top of all the components.

The Lower command sends the selected components to the back of the interface so that they are drawn behind (before) the other components in the interface.

The Font menu contains a set of fonts with which to print text-based components. The default value is the current font from the menu. You also set all the selected components' fonts to that font. A font indicator in the upper-right corner displays the current font.

The Border menu contains a set of brushes that are used to set border widths of Border and Frame components. A border indicator in the upper-left corner displays the current border.

The FgColor and BgColor menus contain a set of colors with which to draw components and text. When you set the current foreground or background color from the FgColor or BgColor menu, you also set all the selected components' foreground or background colors.

The Align menu contains commands to set the alignment of the message on Message-based components. Examples of these components include pull-down and pull-right menus, MenuItem components, and Message components. The effects of alignment are more apparent when the selected components are resized.

Subclasses

Subclasses enable you to introduce user-defined objects for customizing your interfaces. These are abstraction mechanisms that break down complicated user interfaces into more manageable and reusable subcomponents, which are more amenable to user customization. Without subclass objects, the generated code consists of static functions that assemble the library user interface elements into complete interfaces.

The subclasses that you can work with are as listed here :

Member names associated with the components are therefore useless.

With subclass objects, children of a subclass instance become the instance's interior definition. If the interior components are exported, they become member variables of the subclass instance.

Selecting MonoScene Subclass causes each selected component to be enclosed in a MonoScene subclass object.

Selecting Dialog Subclass is similar to selecting MonoScene Subclass, except that it provides features of the Dialog class in the library as well.

Editor Subclass is useful when the end application is a domain-specific editor. Objects kept by an editor, such as the KeyMap, Selection, Component, and ControlState, can all be subclassed to define domain-specific behavior.

Code Generation

Conceptually, components created in the workspace are instances of the actual Interviews and Unidraw counterparts. All separate components (uncomposed and composed components without common parents) generate separate windows after code generation. For example, if the user-specified filename associated with an ibuild session is hello, the files hello-imake, hello-make, hello-props, and hello-main.c are generated.

All user interface components can be subclassed by simply renaming their Class Name attribute to be different from the Base Class Name, using the Examine tool and selecting the Info entry.

A set of four files is generated for each subclassed component in ibuild. If the Class Name of a subclassed component is Displayer, and the Base Class Name is stringEditor, the following files are created: Displayer.h, Displayer.c, Displayer-core.h, and Displayer-core.c as the output of the Generate command.

For the previous set of files, Displayercore is a subclass of stringEditor, and Displayer is a subclass of Displayercore. The -core.* postfixed files are core files that are under ibuild's control, and you should not modify them. These core files contain enhanced widget definitions to accommodate library deficiencies and provide a more convenient user model.

Displayer.h and Displayer.c are subclass files that are provided for customization, which typically involves redefinition of some virtual functions defined by the base class.

The ibuild application also allows the creation of new user interface abstractions by providing MonoScene subclass, Dialog subclass, and Editor subclass composition mechanisms. Typically, the topmost composition of a completed user interface component is a MonoScene subclass object. All enclosed components of a subclass object can be thought of as its members. For instance, if a Dialog subclass instance called Informer is used to wrap (abstract) the previous interface, Informer.h, Informer.c, Informer-core.h, and Informer-core.c are generated. In this case, Informercore is a subclass of Dialog, and Informer is a subclass of Informercore. Like Displayer, Informer-core.h and Informer-core.c are under ibuild's control; Informer.h and Informer.c are for user customization. In addition to providing enhanced widget definitions, Informer-core.c also contains definitions of its appearance by instantiating its member components. Informer-core.h provides an interface to Informer.h where the exported members can be selected by using the Examine tool, as explained later.

Additional Resources in Xdefaults

You must set resources only for the entries that you want to override, not for all of them. If you want to add entries to the menus, simply set resources for them. However, don't skip any numbers after the end of the menu, because the menu ends at the first undefined resource. To shorten a menu instead of extending it, specify a blank string as the resource for the entry following the last item in the menu.

The ibuild application understands the resources listed in Table 33.3, in addition to those specified in idraw.

Table 33.3. Additional resources for ibuild.
Resource Action
initialborder Specifies the border that is active on startup. Give a number that identifies the border by its position in the Border menu starting from 1 for the first entry. Border specification is similar to brush specification in idraw, except only solid brushes should be used because they are used to set border widths of Border and Frame components.
border i Defines a custom border to use for the ith entry in the Border menu. Unlike normal brush specification, the first 16-bit hexadecimal number should always be 0xffff to indicate solid brush. The second hexadecimal number should give the desired border width in pixels. Border specification affects only certain interface objects, as described earlier
.

Building an Application with ibuild

Let's start with a simple application, shown in Figure 33.5. You will build an interface with three check buttons, two push buttons, and a label. The label was created with the Message tool.

FIGURE 33.5. The ibuild sample application.

Collect the check buttons by selecting them and grouping them with the Composition/VBox selection. For the push buttons, use the HBox selection to group them horizontally.

All components of the application were glued together, using the VBOX item, to create one big application. Because this is one screen, attach the Monoscreen composition property to all objects in this application in order to allow all portions of the application screen to be filled with blanks, which are not explicitly covered by an object.

Now, save the application with the File/Save As button. See Figure 33.6 for this dialog box. After saving this application, use the File/Generate option to generate all the source, makefiles, and property files for this application. Now you can build the application as shown in Figure 33.7.

FIGURE 33.6. Saving the sample application.

FIGURE 33.7. Generating files for the sample application.

The following files are created in your current working directory after you are done:

iview/sample1



iview/sample1-imake



iview/sample1-main.c



iview/sample1-main.o



iview/sample1-make



iview/sample1-props




NOTE: If you do not have the TOOLDIR variable defined, you also see a lot of files with the extension Tool. Do not delete them unless you point TOOLDIR to the /usr/Interviews Tools directory. The Tools files provide some interesting insights into how the interface tools work for Interviews.

The version of ibuild on this distribution creates a makefile that fails around line 182, when you try to create the application with a make command. The error is that two makefile variables, SRCS and OBJS, create assignments that do not have a trailing \ for each source file to create. Edit the makefile manually to add these trailing backslashes, or concatenate all the names into one line.

So, the lines

SRCS =



     _MonoScene_5.$(CCSUFFIX)



      _MonoScene_5-core.$(CCSUFFIX)



      sample1-main.$(CCSUFFIX)



OBJS =



      _MonoScene_5.o



      _MonoScene_5-core.o



      sample1-main.o



become the following:

SRCS =   _MonoScene_5.$(CCSUFFIX) \



       _MonoScene_5-core.$(CCSUFFIX) \



       sample1-main.$(CCSUFFIX)



OBJS = _MonoScene_5.o  \



      _MonoScene_5-core.o \



      sample1-main.o



Figure 33.8 shows the makefile for this application generated by the build.

FIGURE 33.8. A sample makefile for this application.


NOTE: Do not forget to edit the makefile to create the correct arguments for the SRCS and OBJS macros.

Now, you can create the application sample1-exe with the following command:

$ make -f sample1-make sample1



This make command spews a lot of messages from the GNU g++ compiler. You should not see any error messages if you have edited your sample1-make file as described earlier. After you have created the application, you can execute this application with this command:

$ sample1



The result of this application is shown in Figure 33.5.


CAUTION: If you do assign the Monoscreen composition to the final VBox or HBox of this application, your application will not fill in any blank areas on the main screen. The result is a semitransparent window of whatever happens to be on the screen at the time and the rest of your application's objects.

CAUTION: Do not forget to group all of your objects together, or each object will have its own independent window.

Adding Interactors

The last order of business for your sample application is to add code to take actions when a button is pressed. This step enables you to attach your own code to your newly created application. A GUI by itself really does not serve any purpose, does it? The code that takes action is called an Interactor.

Add another button to the application you just created, and attach an Interactor to it. Click with the left button on this button, and hold it down. You see two menu items pop up on the mouse cursor. While holding the left button down, move the cursor to the right of this menu to get another list of items, including one titled PushButton. Move the cursor to this item and go left. You are presented with a dialog box (shown in Figure 33.9) showing all the attributes of this push button.

FIGURE 33.9. The PushButton attributes.

Name this push button by typing mybuttonhere in the Member Name box, and check the Export button.

Next, specify the ButtonState instance to use by typing enterBS in the ButtonState dialog. Now click on the ButtonState button to create this instance. See Figure 33.10 for this dialog box.

FIGURE 33.10. Creating the ButtonState instance.

The finished application is shown in Figure 33.11.

FIGURE 33.11. The finished application.

Make sure that the ButtonState is exported, and make entered the name of the function that is called when this button is pressed. Click OK to accept this.

Now, set the setting value of this push button to 1. Click OK to accept it.

Press the left mouse button on the string utility, and then press the left mouse button again on the Info button to get the info for stringEditor. As you did with the push button, create an exported member function called stringEditor. Click OK to accept and dismiss this dialog.

Use the Relate tool to connect the push button to the stringEditor.

Click on the push button, and hold the left mouse button down to select the PushButton item from the pop-up menu that appears. Let go of the mouse button. A line is drawn from this button to your cursor.

Now, move the cursor to the stringEditor, and press the left mouse button again. This brings up another pop-up menu from which you select stringEditor as your target.

The stringEditor is now the target, and the push button is the source. To see whether they are related, use the Examine tool to ensure that the ButtonState name of stringEditor is now enterBS.


NOTE: The order in which you select the relationship is important. The target (stringEditor) receives the ButtonState from the source (pushButton).

The final step is to create the classes that wrap the core around another class. Remember that we created a MonoScreen class as the topmost class for this application. Using the Examine tool, get the info on the Mono_* class for this application. When you get the dialog box for this application, change the Class Name to something else, like Sample1. Click OK to save.

Now, generate the code for this application. You see the following four files listed:

iview/Sample1-core.c



iview/Sample1-core.h



iview/Sample1.c



iview/Sample1.h



Do not edit the *-core files. Edit the Sample1.c and Sample1.h files to create your own functions. The Sample1.h file looks like the one shown in Listing 33.2. The Sample1.c file is shown in Listing 33.3.

Listing 33.2. The Sample 1.h file.

#ifndef Sample1_h



#define Sample1_h







#include "Sample1-core.h"







class Sample1 : public Sample1_core {







public:



    Sample1(const char*);



    virtual void entered();



};



#endif



Listing 33.3. The Sample1.c file.

#include <InterViews/streditor.h>



#include <InterViews/button.h>



#include "Sample1.h"







#include <IV-2_6/_enter.h>







Sample1::Sample1(const char* name) : Sample1_core(name) {}







void Sample1::entered() {



    /* unimplemented */



}



Modify the Sample1.c file to look like Listing 33.4.

Listing 33.4. Adding code to the callback function.

#include <InterViews/streditor.h>



#include <InterViews/button.h>



#include "Sample1.h"



#include <IV-2_6/_enter.h>







#include <stream.h>







Sample1::Sample1(const char* name) : Sample1_core(name) {}







void Sample1::entered() {



    /* Get user input */



      int value;



      enterBS->GetValue(value);



      if (value != 0) {



            cout << stringEditor->Text() << "!\n";



            cout.flush();



            enterBS->SetValue(0);



      }



}



Create the application with the following command:

$ make -f sample1-make sample1.exe



After a long time (depending on the speed of your PC), you will have a sample1.exe application in your directory. Run this program. As you press the center button, you see the cout command execute and print to the standard output.


NOTE: Here's a note about creating Interviews applications from scratch using C++ classes only. Generally, you use the ibuild program to create all your applications with the Interviews libraries. However, there may be times when you want to create small, quick applications using just the base Interviews classes. This step may prove not to be worth the hassle after you are done, because an ibuild application may actually get you quicker results. I have found it easier to just use ibuild than to try to create applications from scratch. Some examples of such from the bottom up applications are available via ftp from the site leland.standford.edu.

Summary

This has been a very short chapter on a very complicated topic: creating Graphical User Interface front ends using C++ and Interviews. The code required for Interviews is based on reusable components. The files for this package are located in the /usr/interviews directory.

You can use idraw to create drawings of icons and learn about the interface tools available to you. Learning to use this tool will help you work with ibuild.

The ibuild application is an Interviews tool that enables you to interactively create C++ applications. ibuild also generates the C++ code for you to run the g++ compiler, or to actually create the makefiles and related source code. The makefiles include a minor bug around line 182 where lines are not connected correctly with a backslash.

The tools available in ibuild can be grouped together using the HBox, VBox and other tools. You can import other functionality for creating Dialogs, File selection boxes, and MonoScenes. By wrapping the application main classes in your own classes, you can add your own C++ (or C) code to any newly created application. You have to be careful which files you edit, because most of the core files are re-created when you modify the interface and regenerate the code. The core subclasses that you create enable you to create more functionality for the core class without having to modify the core GUI classes.