Chapter 6. Advanced Topics

This chapter describes how to select and use interface elements to create your application's interface:

This chapter focuses on choosing appropriate interface elements for your interface rather than discussing the features of each element in detail. For detailed information about the resources available for each interface element, see Appendix A, “RapidApp Reference.”

Work With Windows

Most often, the first step in creating an interface with RapidApp is to select an appropriate window. This is not the case if you're using RapidApp to create only self-contained components. In that case, the window you use to hold your component as you build it is irrelevant; you're interested in the component the window holds.

All of the windows are available on the Windows palette. As shown in Figure 6-1, RapidApp provides a choice of two primary windows—a Simple Window and a VkWindow—and several types of dialogs. This section describes the features of the primary windows and when it's appropriate to use each type. “Work With Dialogs” describes how to incorporate dialogs in your application.

Figure 6-1. The RapidApp Windows Palette



Note: You can also create containers without first creating a top-level window. If you do so, RapidApp automatically provides a top-level shell for the container. However, this shell will not be part of your program. The shell is only a placeholder, necessary to make the container visible in the desktop environment. User interface elements created outside one of the Window containers will be treated as classes, code will be generated, but the object will not be instantiated in the program.

For each type of window, RapidApp automatically provides appropriate Indigo Magic window decorations and window menu entries. See Chapter 3, “Windows in the Indigo Magic Environment,” in the Indigo Magic User Interface Guidelines and Chapter 5, “Window, Session, and Desk Management,” in the Indigo Magic Desktop Integration Guide for information on window decorations and window menu entries.

Simple Windows

As its name implies, a Simple Window is the simplest top-level window. A Simple Window has no menu bar and can contain only one child element. If you want a menu bar for the window, create a VkWindow instead of a Simple Window. The child element that you place in a Simple Window is typically either a container widget or a complex component. You can use Simple Windows as main windows, but typically they're more appropriate as co-primary windows. See “Main Primary and Co-Primary Windows” for more information on main and co-primary windows.

When RapidApp generates code for a Simple Window, it creates it as a subclass of the IRIS ViewKit VkSimpleWindow class. (See Chapter 4, “ViewKit Windows,” in the IRIS ViewKit Programmer's Guide for more information on the VkSimpleWindow class.)

VkWindows

A VkWindow supports far more functionality than a Simple Window. Although it, like the Simple Window, can contain only one child element, a VkWindow includes a menu bar with many of the standard menu bar entries complete with keyboard accelerators (see Chapter 8, “Menus,” in the Indigo Magic User Interface Guidelines for information on standard menu bar entries). You typically use VkWindows as main windows, but you can use them as co-primary windows as well. See “Main Primary and Co-Primary Windows” for more information on main and co-primary windows.

Figure 6-2 shows the default configuration of the VkWindow component.

Figure 6-2. Default Configuration of VkWindow Component


When RapidApp generates code for a VkWindow, it creates it as a subclass of the IRIS ViewKit VkWindow class. (See Chapter 4, “ViewKit Windows,” in the IRIS ViewKit Programmer's Guide for more information on the VkWindow class.)

By default, for each menu item in the menu bar for which you've defined an activateCallback function, RapidApp adds a member function of the same name to the VkWindow's child component or generated class. You can then add the functional code to the functions to define behavior for the menu items. RapidApp doesn't add member functions to the child for those menu items for which you haven't defined an activateCallback function. You can disable this feature by setting the window's autoRouteCallbacks resource to “False.”

Furthermore, for the default items on the File and Edit menus, RapidApp implements some functionality automatically. For example, RapidApp generates code for the “Open” selection of the File menu to display a file selection dialog. You need only take the filename returned by the dialog and perform an open operation appropriate for your application. Table 6-1 summarizes the actions and the functions added for the default items on the File and Edit menus.

Table 6-1. Default Actions of Standard VkWindow Menu Items

Menu

Selection

Function Added to Child Component or Class

Default Action

File

New

newFile()

The child creates a new, empty file.

 

Open

openFile(const char *)

The VkWindow automatically displays a file selection dialog and, if the user selects a file, passes that filename to the child as an argument to the openFile() function. The child opens the given file.

 

Save

save()

The child saves its current state to the current file.

 

Save As

saveas(const char *)

The VkWindow automatically displays a file selection dialog and, if the user selects a file, passes that file name to the child as an argument to the saveas() function. The child saves its current state to the specified file.

 

Print

print(const char *)

The child prints its contents. Currently, the argument to print() is unused.

 

Close

 

The VkWindow deletes itself. To change this behavior, edit the close() function of the VkWindow subclass.

 

Exit

 

The VkWindow calls VkApp:quitYourself() to exit the application. (See Chapter 3, “The ViewKit Application Class,” in the IRIS ViewKit Programmer's Guide for more information on the VkApp class.) To change this behavior, edit the quit() function of the VkWindow subclass.

Edit

Undo

 

The VkWindow automatically invokes the undo functionality provided by the IRIS ViewKit VkMenuUndoManager class. (See Chapter 6, “ViewKit Undo Management and Command Classes,” in the IRIS ViewKit Programmer's Guide for more information on the VkMenuUndoManager class.) You can't override this behavior; if you don't want to support undo in your application, remove this menu item.

 

Cut

cut()

The child cuts its current selection to the clipboard. See Chapter 5, “Data Exchange on the Indigo Magic Desktop,” in the Indigo Magic User Interface Guidelines for guidelines and Chapter 7, “Interapplication Data Exchange,” in the Indigo Magic Desktop Integration Guide for instructions on implementing cut and paste in your application.

 

Copy

copy()

The child copies its current selection to the clipboard. See Chapter 5, “Data Exchange on the Indigo Magic Desktop,” in the Indigo Magic User Interface Guidelines for guidelines and Chapter 7, “Interapplication Data Exchange,” in the Indigo Magic Desktop Integration Guide for instructions on implementing cut and paste in your application.

 

Paste

paste()

The child retrieves the contents of the clipboard and inserts it as appropriate. See Chapter 5, “Data Exchange on the Indigo Magic Desktop,” in the Indigo Magic User Interface Guidelines for guidelines and Chapter 7, “Interapplication Data Exchange,” in the Indigo Magic Desktop Integration Guide for instructions on implementing cut and paste in your application.

You can add, edit, and remove menu panes and menu items if you want. For more information on manipulating menus in RapidApp, see “Work With Menus”.


Note: Don't remove or edit the Help menu using RapidApp. The VkWindow class automatically creates a standard Help menu that interfaces with the Silicon Graphics help system; RapidApp ignores any changes that you make to the Help menu. For more information on the standard Help menu, see Chapter 5, “Creating Menus With ViewKit,” in the IRIS ViewKit Programmer's Guide.

If your application doesn't include online help, you can disable the Help menu by setting the window's hideHelpMenu resource to True.

Main Primary and Co-Primary Windows

Chapter 3, “Windows in the Indigo Magic Environment,” of the Indigo Magic User Interface Guidelines describes two types of primary windows recommended for use in Indigo Magic Desktop applications: main primary windows and co-primary windows:

  • A main primary window serves as the application's main controlling window. It's used to view or manipulate data, get access to other windows within the application, and kill the process when users quit. You should have only one main primary window per application.

  • A co-primary window is used for major data manipulation or viewing of data outside of the main window. Co-primary windows are often used as “auxiliary” windows and are not displayed automatically on starting the application.

RapidApp allows you to set the type of a Simple Window or a VkWindow with the coprimaryWindow resource, as shown in Figure 6-3.

Figure 6-3. Setting the Window Type


Chapter 3 of the Indigo Magic User Interface Guidelines recommends different entries in the window menu (that is, the menu in the title bar added by the window manager) based on the type of window. RapidApp automatically generates the necessary code to configure a window based on the value of the coprimaryWindow resource that you select.

RapidApp automatically instantiates and displays all main windows in main.C. However, it doesn't create instances of or display co-primary windows in your application. You need to instantiate co-primary windows explicitly and use the show() member function to display them when appropriate. For example, if you display a co-primary window based on an action in another component, you can declare the co-primary window as a protected data member of the component:

protected:
  CoprimaryMainWindow * _coprimary;

Then instantiate the co-primary window in the component's constructor:

_coprimary = new CoprimaryMainWindow("coPrimary");

When you need to display the co-primary window, call its show() member function:

_coprimary->show();

See Chapter 4, “ViewKit Windows,” in the IRIS ViewKit Programmer's Guide for more information on manipulating windows using the window class member functions.

Adding New Top-Level Window Layouts to RapidApp

The VkWindow user interface element provided on RapidApp's Windows palette is somewhat different from many other elements on RapidApp's palettes. The VkWindow (and VkSimpleWindow) elements are not individual widgets, and are not classes. They are simply templates, created as a collection of other widgets, that can be altered and extended to meet your needs. RapidApp treats these windows specially, so that they ultimately become a C++ class, derived from VkWindow or VkSimpleWindow, but at the beginning, these elements are simply a description of a particular combination of widgets.

The VkWindow template has been chosen to conform to the SGI user interface guidelines, and provides menu entries that are often useful. However, you may find that you have additional or simply different menu items that you would like to use repeatedly, and would like to avoid having to start with a VkWindow and make the same modifications each time you need a window.

RapidApp allows you to edit a VkWindow object once, and save the results as a template that can be used any time you want the same interface. To create and save a template, follow these steps:

  1. Start RapidApp and click on the VkWindow icon.

  2. Edit the window however you like.

  3. Select “Save As...” from the File menu.

  4. Supply the name of a file in which to save your work, as normal.

  5. Before clicking on OK, change the option menu on the File dialog to read “Window Template”. Then click on OK.

  6. When a dialog appears, type by which you would like this template to be known on the RapidApp palette. Then click on OK.

  7. Exit and restart RapidApp. Your template should appear on the Windows palette. Classes created from this template will be derived from VkWindow (or possibly other classes) the same as the built-in template. However, the contents of the window are defined by your template, plus any changes you make when using the template.

Work With Containers

Once you have created a top-level window, you can “populate” it with interface elements. Because all of the top-level windows accept only one child element, that child element is almost always either a container or a complex component. This section describes how to choose appropriate containers to group and manage other elements. “Work With User-Defined Components” discusses how to use components, but even in that case, you must understand how to choose an appropriate container to serve as the top-level element of a component. All of the containers are available on the Containers palette, shown in Figure 6-4.

Figure 6-4. RapidApp Containers Palette


One of the challenges of working with IRIS IM is choosing an appropriate container to achieve the layout you would like. Many simpler systems give you only one type of container which requires you to place each component at a specific location within it. On these systems, if you want your interface to exhibit any type of dynamic behavior—allow users to resize windows, support internationalization (which requires dynamic layouts to handle different sized labels in different languages), allow users to customize portions of the user interface, and so on—you have to implement the support yourself.

IRIS IM does much more to help you with such requirements by providing a variety of containers that arrange their children in different ways. You can use IRIS IM containers to control the relationship of elements they contain. For example, you can left-align a group of elements, or you can create groups of elements such that the width of the largest element determines the width of the entire group. However, this flexibility adds more complexity. Instead of simply positioning widgets manually, you must position them by choosing and manipulating the right container. Furthermore, the IRIS IM containers were not designed with an interface builder in mind, and don't always behave as you might expect in response to interactive manipulation.


Note: Many containers add constraints to the elements they contain—resources that affect the appearance or behavior of an element within its container. These constraint resources appear on the children, not on the container. Different containers add different constraints, so you might see a constraint resource in one interface element and not in another of the same type if the elements are contained within different types of containers. The resource editor area lists constraint resources separately from other resources, below a label identifying them as constraint resources. You can modify constraint resources just as you do other resources.


Bulletin Board

The Bulletin Board widget (XmBulletinBoard) is the simplest IRIS IM container and the easiest to use. You simply “tack” elements to a particular position in the Bulletin Board and they stay there unless you explicitly move them. The Bulletin Board doesn't reposition or resize its children for any reason. Using a Bulletin Board container is the most like working with a drawing editor.

The limitation of a Bulletin Board is that all positions and sizes are fixed. For example, if you change the text or font of a label in a resource file, the label could grow or shrink, altering its alignment to other elements. Because of this limitation, the Bulletin Board is a poor choice for programs that you expect to internationalize or to allow users to customize the interface. Also, don't use a Bulletin Board if you want to allow the user to stretch or shrink the interface size. However, the Bulletin Board is a good choice for quickly prototyping interface designs because it is easy to use and provides the greatest flexibility for arranging elements within it.


Note: The Bulletin Board supports marginWidth and marginHeight resources that enforce minimum offsets from the edges of the container to its child elements. However, the Bulletin Board wasn't designed with an interactive builder in mind, so after initially placing an element you can move it closer to the edge of the Bulletin Board than allowed by the margin values. But when you run your application, the Bulletin Board overrides the children's positions and places them within the margins, resulting in a layout slightly different from what you specified in RapidApp. Therefore, either obey the margins when placing and moving elements, or change the marginWidth and marginHeight resources if you prefer smaller margins.

See the XmBulletinBoard(3Xm) reference page for more information on the XmBulletinBoard widget.

Rubber Board

The Rubber Board widget (SgRubberBoard) is an IRIS IM extension to Motif. The Rubber Board is similar to a Bulletin Board and shares both its ease of use and some of its limitations. However, it has a unique ability to support resizable layouts simply and easily. This widget is also designed explicitly for use with an interface builder; it would be awkward to use programmatically.

To use the Rubber Board:

  1. Create an instance of it as small as you reasonably expect your window to be. For best results, make this as small as possible.

  2. Place child elements on the Rubber Board just as you would a Bulletin Board.

  3. Select the Rubber Board and toggle its setInitial resource to True.

  4. Stretch the window until it is as large as possible (full screen is best).

  5. Reposition and resize all the children so that the layout is as you would want it to appear if the user resized the window to that size.

  6. Select the Rubber Board and toggle the setFinal resource to True.

  7. Toggle on the autoPosition resource. From this point on, the Rubber Board interpolates the positions and sizes of all its children as it resizes.


Note: The Rubber Board responds to changes in size initiated only by its parent (for example, its parent window); it doesn't respond to changes in the size of its children. Therefore, the Rubber Board continues to have the same limitations with respect to changing fonts, labels, or internationalization as the Bulletin Board.

The Rubber Board widget interpolates both size and position. In theory you can create bizarre dynamic behavior in which widgets move unexpectedly in response to resizing. For example, a widget on the right side of the Rubber Board when the container is small can move slowly to the left side as the Rubber Board grows larger. For obvious reasons, avoid using the Rubber Board in this manner.

You can nest Rubber Boards within one another. To do so, it's best to design the resize behavior of the inner containers first, and then place them in the larger Rubber Board.


Tip: The Rubber Board doesn't handle certain errors well, such as making the final size smaller than the initial size. Therefore, create the initial layout with the Rubber Board as small as possible, even if the size is unrealistic. Similarly, create the final size as large as possible.

Figure 6-5 through Figure 6-8 demonstrate the behavior of the Rubber Board widget. To begin, create an interface in a small container, such as in Figure 6-5. Once you've finished the layout, set the Rubber Board's setInitial resource to True.

Figure 6-5. Rubber Board: Initial Layout


Next, resize the Rubber Board to a much larger size, as in Figure 6-6. Notice that all widgets keep their original size and position.

Figure 6-6. Rubber Board: Preparing for Larger Layout


Then resize and reposition the elements to reflect their desired size and position for the larger container size, as shown in Figure 6-7.

Figure 6-7. Rubber Board: Final Layout


After setting the Rubber Board's setFinal and autoPosition resources, you can resize the Rubber Board to any shape and the children will maintain their relative positions and sizes, as demonstrated in Figure 6-8.

Figure 6-8. Effect of Resizing the Final Rubber Board Layout


Spring Box

The Spring Box widget (SgSpringBox) is an IRIS IM extension to Motif. At its simplest, the Spring Box simply enforces row or column behavior on its child elements. Figure 6-9 shows two simple layouts with buttons placed in vertical and horizontal Spring Boxes.

Figure 6-9. Vertical and Horizontal Spring Boxes


What you can't see from Figure 6-9 is that each child of the Spring Box has six springs associated with it. Each spring has an associated “spring constant” value, which combines with the other springs to determine the overall behavior of the spring system. You can control each spring individually.

By default, the value of the horizontal and vertical spring resources are set to 100, while the other springs are set to 0. This means the children of the Spring Box stretch to fill the size of the Spring Box.

You can change the values of the spring resources by selecting a child and changing its constraint resources, as shown in Figure 6-10.

Figure 6-10. Setting Spring Resources


For example, consider the behavior if you set up the spring values as shown in the following table:

Table 6-2. Spring Values

Spring

button1

button2

button3

leftSpring

0

0

0

rightSpring

0

0

0

topSpring

0

0

0

bottomSpring

0

0

0

verticalSpring

100

100

100

horizontalSpring

0

100

0

Figure 6-11 shows the layout created by these values, both when the Spring Box is its natural size and when it is stretched.

Figure 6-11. Spring Box Behavior With Modified Values


To create complete layouts using the Spring Box, you usually need to nest Spring Boxes within Spring Boxes, mixing vertical and horizontal orientations.

As a convenience, the Spring Box container itself includes two resources, defaultHorizontalLayout and defaultVerticalLayout, to help you create common layouts. Settings these resource causes the Spring Box container to apply a collection of resource settings to all the children it currently contains. Each resource is independent and controls only the resources that apply vertically or horizontally. The meaning of these resources does not change with the value of the orientation resource (that is, vertical is always vertical). Possible layouts include:

XmCENTER 

Centers all children in the middle of the Spring Box, with equal spacing on either side of the entire group of children.

XmSPAN 

Stretches all children equally to fill the entire space of the Spring Box.

XmLEFT 

Sets all children to their natural size and moves them to the left edge of the Spring Box. Applies only to the defaultHorizontalLayout resource.

XmRIGHT 

Sets all children to their natural size and moves them to the right edge of the Spring Box. Applies only to the defaultHorizontalLayout resource.

XmTOP 

Sets all children to their natural size and moves them to the top edge of the Spring Box. Applies only to the defaultVerticalLayout resource.

XmBOTTOM 

Sets all children to their natural size and moves them to the bottom edge of the Spring Box. Applies only to the defaultVerticalLayout resource.

XmDISTRIBUTE 


Sets all children to their natural size and distributes them evenly across any open space in the Spring Box.

XmSTRETCH_FIRST 


Allows the first (left-most or top-most) child to stretch freely to fill any available space. All others are set to their natural size.

XmSTRETCH_LAST 


Allows the last (right-most or bottom-most) child to stretch freely to fill any available space. All others are set to their natural size.

XmIGNORE 

Ignores the default setting and uses the custom values of each individual child's spring resources.

The Spring Box container uses the creation order of its children to determine their positions. You can move a child to a different position by selecting it and then using the “Up/Left” (or the <Ctrl+u>, <Left arrow>, or <Up arrow> keyboard shortcut) and “Down/Right” (or the <Ctrl+d>, <Right arrow>, or <Down arrow> keyboard shortcut) selections from the Edit menu.

The Spring Box tends to wrap itself tightly around its children, so that you can't select or move it directly. To access the Spring Box, select a child of the Spring Box widget, then choose “Select Parent” from the Edit menu (or type the <Ctrl+p> keyboard shortcut) to select the Spring Box widget. You can then access the Spring Box's resources. To move or resize the Spring Box, hold down the <Ctrl> key while using the left mouse button as you normally would. The <Ctrl> key prevents RapidApp from selecting a new element so that you can easily manipulate the currently selected element.

Form

The Form widget (XmForm) is the most common choice for resizable layouts. The Form widget positions its children based on attachments. For example, you can attach an element to a percentage position in the Form, to the side of another element, and so on. Forms can respond to resizes initiated by both its parent (for example, its parent window) and its children.

The traditional problem with Forms is that they are difficult to set up and use. Programmatically setting all the attachment resources for the Form's children is tedious, and it's difficult to envision the resulting appearance. RapidApp makes Forms easier to use by allowing you to interactively edit attachments and see the results.


Tip: Although you can create complex layouts within a Form widget, often it's simpler to create simple layouts with only a few widgets, define that collection as a component, and then group the component with other components in a parent Form.

The easiest way to understand how to manipulate elements within a Form is by example. Figure 6-12 shows what happens when you add a push button to a Form.

Note the symbols around the push button and the lines from the button to the edge of the Form. The symbols are called attachment icons; there is one for each side of a child in a Form. The lines represent attachments. In this case, the button is attached to the top and left sides of the Form and is unattached on the right and bottom. This is the default behavior for an interface element placed in a Form.

Figure 6-12. Push Button in a Form


The length of the line represents the offset from the point of attachment to the element. You can vary this offset in several ways. First, you can simply move the element. For example, moving the push button to the top of the window as shown in Figure 6-13 sets the top offset to zero.

Figure 6-13. Setting the Top Offset to Zero


You can also set the offset by holding down the <Shift> key and pressing the left mouse button over an attachment icon. RapidApp displays a menu showing the value of the offset. You can change this value by moving the mouse while continuing to hold down the <Shift> key and left mouse button. Figure 6-14 shows an example.

Figure 6-14. Using the Popup to Set an Offset


Alternatively, you can change the value of the offset in the appropriate field of the resource editor when the child element is selected.

You can change the type of an attachment by pressing the right mouse button over the attachment icon. RapidApp displays a menu showing the attachment type choices. For example, Figure 6-15 demonstrates pressing the right mouse button over the right attachment icon. Figure 6-16 shows the results of selecting XmATTACH_FORM.

Figure 6-15. Displaying the Attachment Menu


Figure 6-16. Push Button With a Right Attachment


Another way to create or edit an attachment is by dragging from an attachment icon to another interface element. For example, add a second push button to the Form, near the bottom of the container. Now press the left mouse button over the new button's top attachment icon and drag to the bottom edge of the original button, as shown in Figure 6-17.

Figure 6-17. Drawing an Attachment


The XmATTACH_POSITION attachment type allows you to set the position of the element within a Form relative to the size of the Form. For example, you can specify the position of an element so that its top is always one quarter of the way from the top of the Form no matter what size the Form takes. To do this, you must specify two resource values: a numerator (in the interface element) and a denominator (in the Form). The denominator is the fractionBase resource in the Form. You can set the numerator either interactively, in the same way that you set the offset, or by changing the appropriate position resource when the child element is selected.


Note: If you use position attachments, be sure to set the value of the fractionBase resource before setting the attachments of any children to XmATTACH_POSITION. A Form doesn't recompute the children's position attachments if you change the Form's fraction base.

See the XmForm(3Xm) reference page for more information on the XmForm widget.

Paned Windows

The IRIS IM Paned Window widget (XmPanedWindow) places all its children in a column with each widget separated by a control, known as a sash, and an optional separator. The user can drag the sash to adjust the height of a section. The Paned Window widget adds constraint resources to each child that you can use to specify a minimum or maximum size. The Paned Window is suitable for interfaces that contain panels of information that the user might want to hide, reveal, or enlarge separately. See the XmPanedWindow(3Xm) reference page for more information on the XmPanedWindow widget.

The HPaned Window widget (SgHorzPanedWindow) is an IRIS IM extension to Motif. This widget is identical in functionality to the XmPanedWindow widget, but arranges its children in a horizontal row with separators and sashes between each child. Figure 6-18 shows an example of the HPaned Window.

Figure 6-18. HPaned Window Container


The Paned Window containers use the creation order of their children to determine their positions. You can move a child to a different position by selecting it and then using the “Up/Left” (or the <Ctrl+u>, <Left arrow>, or <Up arrow> keyboard shortcut) and “Down/Right” (or the <Ctrl+d>, <Right arrow>, or <Down arrow> keyboard shortcut) selections from the Edit menu.

Because these Paned Window containers weren't designed with an interactive builder in mind, they might exhibit some odd behaviors in RapidApp.

  • If you add a single child to the Paned Window, you can no longer click the Paned Window to edit its resources or add another child. To select the Paned Window, select a child of the Paned Window, then choose “Select Parent” from the Edit menu (or use the <Ctrl+p> keyboard shortcut). You can then access the Paned Window's resources. To move or resize the Paned Window, hold down the <Ctrl> key while using the left mouse button as you normally would. The <Ctrl> key prevents RapidApp from selecting a new element so that you can easily manipulate the currently selected one.

  • The easiest way to add more child elements to the Paned Window is to select the Paned Window and to toggle on “Keep Parent” in the View menu. You can then add as many children to the Paned Window as you want. When you are finished adding children, toggle off “Keep Parent.”

  • After you add the first child, all subsequent children that you add have zero height. Furthermore, if you reorder the Paned Window's children, the Paned Window might resize some of the children, possibly even to a zero height. To get around this either: 1) as soon as you add a child, edit its minHeight resource to be a larger size; or 2) move the sash(es) so all children are the desired size.

RowColumn

The primary purpose of the RowColumn widget (XmRowColumn) is to support menu panes and menu bars. It also has limited use for simple aligned rows, and can support multiple columns as well. However, the RowColumn container forces all of its children to have the same height, and it provides only limited ability to control how children are resized. If you want a layout like that shown in Figure 6-19, then the RowColumn widget is a good choice. Otherwise, you might want to choose another container.

Figure 6-19. Typical RowColumn Layout


The RowColumn container uses the creation order of its children to determine their positions. You can move a child to a different position by selecting it and then using the “Up/Left” (or the <Ctrl+u>, <Left arrow>, or <Up arrow> keyboard shortcut) and “Down/Right” (or the <Ctrl+d>, <Right arrow>, or <Down arrow> keyboard shortcut) selections from the Edit menu.

The RowColumn container tends to wrap itself tightly around it children, so that it cannot be selected or moved. To select the RowColumn container, select a child of the RowColumn widget, then choose “Select Parent” from the Edit menu (or use the <Ctrl+p> keyboard shortcut). You can then access the RowColumn's resources. To move or resize the widget, hold down the <Ctrl> key while using the left mouse button as you normally would. The <Ctrl> key prevents RapidApp from selecting a new element so that you can easily manipulate the currently selected one.

See the XmRowColumn(3Xm) reference page for more information on the XmRowColumn widget.

Radio Box

The Radio Box container is really a RowColumn container. It enforces radio behavior (one-of-many) on all toggle buttons it contains. The Radio Box is useful for small rows or columns of one-of-many radio buttons, as shown in Figure 6-20.

Figure 6-20. Radio Box With Toggle Button Children


When you create a Radio Box, RapidApp automatically creates two toggle buttons as children. In all other aspects, the Radio Box behaves the same as a RowColumn container (see “RowColumn” for more information).

Frame

The Frame widget (XmFrame) is a purely decorative container, drawing a frame around its contents. A Frame can contain two children. One is the work area child, the widget surrounded by the Frame. The other is an optional label widget. The Frame places the label at the top, in-line with the frame, as shown in Figure 6-21. You can change its position slightly by editing the label's constraint resources added by the Frame.

Figure 6-21. Frame Widget



Tip: It's easiest to add the title label widget first. RapidApp initially places the label in the middle of the Frame as the work area child. You need to change the label widget's childType constraint resource (added by the Frame) to XmFRAME_TITLE_CHILD. Once the title is in place, you can then add the work area widget for the Frame—typically, a container or a component.

See the XmFrame(3Xm) reference page for more information on the XmFrame widget.

Scrolled Window

The Scrolled Window widget (XmScrolledWindow) adds scroll bars to a child element. The Scrolled Window can contain only one child, typically a container or a component.

See the XmScrolledWindow(3Xm) reference page for more information on the XmScrolledWindow widget.

Drawing Areas

RapidApp provides three drawing area widgets: Drawing Area (XmDrawingArea), Visual Drawing (SgVisualDrawingArea), and GLDraw (GLwMDrawingArea). The Drawing Area and Visual Drawing widgets provide a canvas on which you can draw using Xlib library calls; the Visual Drawing widget is an IRIS IM extension to Motif; it allows the widget to use a visual different from the rest of the application.


Note: Although both the Drawing Area and Visual Drawing widgets can function as simple containers, similar to the Bulletin Board, use these widgets only for drawing rather than managing other widgets. Other containers are more appropriate for managing child widgets.

See the XmDrawingArea(3Xm) reference page for more information on the XmDrawingArea widget. See the SgVisualDrawingArea(3Xm) reference page for more information on the SgVisualDrawingArea widget. See the GLwMDrawingArea(3Xm) reference page for more information on the GLwMDrawingArea widget.

Tabbed Deck

The Tabbed Deck component (VkTabbedDeck) is a special container that arranges any number of child elements in a “deck.” The Tabbed Deck component displays only one child at a time, but also displays a tab area, with one tab for each child. The user can click a tab to display the corresponding child. Figure 6-22 shows an example of a Tabbed Deck.

Figure 6-22. Tabbed Deck


You can add any number of child elements to the Tabbed Deck. Each element automatically fills the entire area of the Tabbed Deck except for the tab area.


Tip: After adding the first child element to a Tabbed Deck, add other elements by dropping them over the tab area.

The Tabbed Deck creates a tab for each element you add. You can display an element, even in Build Mode, by selecting its corresponding tab. To change the text of an element's tab, select the element and edit the tabLabel constraint resource added by the Tabbed Deck.

When RapidApp generates code for a Tabbed Deck, it creates it as a subclass of the IRIS ViewKit VkTabbedDeck class. Furthermore, for each child of the Tabbed Deck that isn't a component (that is, a C++ class), RapidApp automatically encapsulates that child and its contents within a subclass of VkComponent. (See Chapter 2, “Components,” in the IRIS ViewKit Programmer's Guide for more information on the VkComponent class.) The Tabbed Deck then simply creates an instance of that class.


Note: There is currently no way to reorder the children's positions within the Tabbed Deck. Be sure to add the children in the order in which you want them to appear in the tab area.


Work With Menus

The menus palette, shown in Figure 6-23, allows you to create menus and menu items. RapidApp allows you to create and manipulate both menu bars and option menus.

Figure 6-23. RapidApp Menus Palette


Menu Bars

A menu bar consists of a collection of cascade buttons at the top of a window with pulldown menus (also referred to as menu panes) connected to them. This section describes how to create and edit menu bars using RapidApp. See “Menu Panes” for information on editing the contents of individual menu panes.

Creating a Menu Bar

The only way to create a menu bar on a main window in RapidApp is to create a VkWindow. You can't add a menu bar to a simple window after you create it.


Tip: If you build an interface in a simple window and later decide that you want a menu bar for the window, you can create a new VkWindow, cut or copy the top-level child (and thus everything it contains) of the existing simple window, and paste the interface into the new VkWindow.

When you create a VkWindow, RapidApp automatically includes a menu bar with many of the standard menu bar entries implemented complete with keyboard accelerators. See “VkWindows” for more information on the standard menu bar entries.

You can add a menu bar to a dialog if you want a custom dialog. To do so, select the Menu Bar element from the Menus palette and add it to the desired dialog as you would any other element. This menu bar doesn't contain the standard menu bar entries described in “VkWindows”; instead, it contains only two dummy menu panes with three dummy menu entries each. See “Creating and Using Custom Dialogs” for more information on creating custom dialogs.

Adding Panes to a Menu Bar

Add panes to a menu bar just as you add other elements to a container First, select the menu bar. Then click with the left mouse button on the icon on the menus palette of the type of pane you want to add, then click with the left mouse button within the menu bar to add the item. Alternatively, you can click the icon with the middle mouse button, drag the item to the menu bar, then release the mouse button.

You can add the following two items to a menu bar:

Pulldown menu 


A regular menu pane. For your convenience, RapidApp automatically adds three initial menu entries to the pulldown menu. You can edit these items as described in “Menu Panes”.

Radio pulldown 


A menu pane that enforces radio behavior (one-of-many) on all toggles that it contains. For your convenience, RapidApp automatically adds three dummy menu toggles to the pulldown menu. You can edit these items as described in “Menu Panes”.


Tip: A convenient way to add multiple panes to a menu bar is to select the menu bar and then toggle on “Keep Parent” on the RapidApp View menu. RapidApp grays out all inapplicable items on the Menus palette, leaving active only those items you can add to a menu bar. You can then left-click an icon and drop it anywhere on the screen; RapidApp still adds the item to the selected menu bar.

After adding a menu pane, you can use the RapidApp resource editor to change the menu's label and mnemonic.

Removing Panes From a Menu Bar

Remove menu panes just as you do any other element in RapidApp. Simply select the cascade button in the menu bar for that menu pane, then cut it or delete it.

Moving Panes In a Menu Bar

To move a menu pane in a menu bar, select the cascade button in the menu bar for that menu pane, then use the “Up/Left” (or the <Ctrl+u>, <Left arrow>, or <Up arrow> keyboard shortcut) and “Down/Right” (or the <Ctrl+d>, <Right arrow>, or <Down arrow> keyboard shortcut) selections from the Edit menu.

Menu Panes

This section describes how to build individual menus—that is, the contents of individual menu panes.

Displaying and Hiding a Menu's Contents

When running an application, menus are transitory: they appear only when posted and disappear after the user makes a selection. Of course, this isn't useful when creating and editing menus, so RapidApp can display a menu continuously while you are constructing it.

Once you select a menu's cascade button, clicking on it again with the left mouse button causes RapidApp to display the menu's contents. Subsequent clicks toggle the display of the menu's contents off and on. Once you display the menu's contents, you can select and manipulate individual menu items as you would any other element in RapidApp. You can display multiple menus at once, and even drag and drop menu items between menus.

Adding Items to a Menu

You add items to a menu just as you add elements to a container (in fact, the menu pane container is simply a RowColumn widget). First, select the menu or any item in the menu. Then click with the left mouse button on the icon on the menus palette of the type of item you want to add, then click with the left mouse button within the menu to add the item. Alternatively, you can click the icon with the middle mouse button, drag the item to the menu, then release the mouse button.

You can add the following items to a menu:

Menu entry 

A selectable action (implemented as a an XmPushButtonGadget)

Confirm first 

A selectable entry that posts a confirmation dialog before executing the action. Confirm First menu items don't support an undoCallback resource.

Menu toggle 

A selectable toggle entry. To enforce radio behavior on a group of toggles within a menu, put them within a Radio Pulldown menu.

Label 

A non-selectable label.

Separator 

A non-selectable separator.

Pulldown menu 


A cascading, or pull-right, menu. For your convenience, RapidApp automatically adds three initial menu entries to the pulldown menu.

Radio pulldown 


A cascading menu that enforces radio behavior (one-of-many) on all toggles that it contains. For your convenience, RapidApp automatically adds three initial menu toggles to the pulldown menu.


Tip: A convenient way to add multiple items to a menu is to select the menu (select any item in the menu, then choose “Select Parent” from the RapidApp Edit menu), then toggle on “Keep Parent” on the RapidApp View menu. RapidApp grays out all inapplicable items on the Menus palette, leaving active only those items you can add to a menu bar. You can then left-click an icon and drop it anywhere on the screen; RapidApp still adds the item to the selected menu.

After adding an item, you can use the RapidApp resource editor to change the item's label and mnemonic. For each item that invokes an action—Menu Entry, Confirm First, and Menu Toggle—you must define an activateCallback function that your application invokes when the user selects the item. For Menu Entry and Menu Toggle items, you can also define an undoCallback function that your application can invoke to undo the effects of the item's action.

For each menu item in a menu pane, RapidApp adds a member function of the same name to the VkWindow's child component. You can then add the functional code to the functions to implement the menu items.

Moving Items in a Menu

To move an item in a menu, select the item and use the “Up/Left” (or the <Ctrl+u>, <Left arrow>, or <Up arrow> keyboard shortcut) and “Down/Right” (or the <Ctrl+d>, <Right arrow>, or <Down arrow> keyboard shortcut) selections from the Edit menu.

Removing Items From a Menu

Remove items from a menu just as you do other elements in RapidApp. Simply select the menu item, then cut it or delete it.

Option Menus

An option menu is an interface element that allows the user to select one of several options using a menu. An option menu consists of a label and the equivalent of a cascading menu. When not displaying the cascading menu, an option menu displays the last item the user selected.

You create an option menu just as you do other interface elements. A newly created option menu has no label. To work with an option menu more easily, immediately edit the option menu's labelString resource to provide a label.

You can click anywhere on the option menu's label or cascade button to display its cascading menu pane. RapidApp automatically adds two dummy menu entries to the option menu when you create it. You can edit the option menu pane as described in “Menu Panes”.

Work With Dialogs

By comparison to other parts of your interface, there is little to customize for most dialogs. In fact, IRIS IM includes standard dialogs for uses such as warnings, errors, and file selection. You simply need a way to specify a message and title, post and dismiss the dialog, and perhaps retrieve a value. Furthermore, dialogs are rarely posted as a result of specific user interaction such as clicking a button; instead, they are often a result of error conditions or other program states.

As a result, standard dialogs are not well suited for construction with RapidApp. In most cases, you should use the dialog management system provided by IRIS ViewKit. (For more information on the IRIS ViewKit dialog mechanism, see Chapter 7, “Using Dialogs in ViewKit,” in the IRIS ViewKit Programmer's Guide.) However, RapidApp supports a method for creating customized dialogs that use the IRIS ViewKit dialog management system.

This section describes:

  • using the IRIS ViewKit dialog management system for standard dialogs

  • creating and using custom dialogs with RapidApp

Using the IRIS ViewKit Dialog System for Standard Dialogs

IRIS ViewKit implements a complete dialog management system including:

  • caching and reusing dialogs to improve application performance

  • single function mechanisms for posting dialogs

  • ability to post any dialog in non-blocking, non-modal mode; modal mode; and two blocking modes

  • positioning in multiwindow applications

  • posting of dialogs even when windows are iconified, if desired

  • correct handling of dialog references when widgets are destroyed

The IRIS ViewKit dialog mechanism handles all standard dialog types including information, warning, error, busy, question, prompt, file selection, and preference dialogs. IRIS ViewKit encapsulates dialog management, including caching, in the abstract VkDialogManager class that serves as a base class for other, specific dialog classes. Each type of dialog in IRIS ViewKit has a separate class derived from VkDialogManager. Each class is responsible for managing its own type of dialog (for example, each class maintains its own dialog cache).

The header file for each dialog class provides a global pointer to the instance of that class's dialog manager. The name of the pointer consists of “the” followed by the dialog type. For example, the global pointer to the information dialog manager declared in <Vk/VkInfoDialog.h> is theInfoDialog, the global pointer to the error dialog manager declared in <Vk/VkErrorDialog.h> is theErrorDialog, and so forth. To access the dialog managers in your application, simply use these global pointers.

The VkDialogManager class offers four different functions for posting dialogs:

post() 

Posts a non-blocking, non-modal dialog. The function immediately returns, and the application continues to process user input in all windows.

postModal() 

Posts a non-blocking, full-application-modal dialog. The function immediately returns, but the user cannot interact with any application windows until after dismissing the dialog.

postBlocked() 

Posts a blocking, full-application-modal dialog. The user cannot interact with any application windows until after dismissing the dialog. Furthermore, the function does not return until the user dismisses the dialog.

postAndWait() 

Posts a blocking, full-application-modal dialog. The user cannot interact with any application windows until after dismissing the dialog. Furthermore, the function does not return until the user dismisses the dialog. postAndWait() is simpler to use than postBlocked(), but it does not allow as much programming flexibility.

Each function accepts arguments for setting the dialog message, callback functions for each button on the dialog, and other parameters. The VkDialogManager class also offers functions for setting the dialog's title, setting the labels for its buttons, programmatically dismissing the dialog, and other actions. For more information on the IRIS ViewKit dialog mechanism, see Chapter 7, “Using Dialogs in ViewKit,” in the IRIS ViewKit Programmer's Guide. You can also consult the VkDialogManager(3Vk) reference page for more information on the functions provided by the VkDialogManager class.

Creating and Using Custom Dialogs

Occasionally, you might need to create a custom dialog not implemented in IRIS ViewKit. You can use any of the dialogs on the Windows palette as the basis for a custom dialog. Any custom dialog that you create with RapidApp integrates with the IRIS ViewKit dialog mechanism; you post, dismiss, and otherwise interact with them in your application in the same way as the predefined IRIS ViewKit dialogs.

Selecting a Dialog to Customize

You can use any of the standard dialogs on the Windows palette as the basis for a custom dialog. If none of the predefined dialog types are appropriate, you can start with the Dialog Window element. Figure 6-24 shows the default configuration of a Dialog Window. The Dialog Window is ideal for implementing support windows, which are described in Chapter 3, “Windows in the Indigo Magic Environment,” in the Indigo Magic User Interface Guidelines.

Figure 6-24. Default Configuration of Dialog Window


Adding Elements to the Dialog

In addition to the standard elements provided by the dialog you select to begin with, you can add one child element. The child element that you place in a dialog is typically either a container widget or a complex component.

Adding a Menu Bar to the Dialog

You can also add an optional menu bar to your customized dialog. To do so, go to the Menus palette, select the Menu Bar element, and add it as a child of the dialog. You can then edit the Menu Bar as described in “Work With Menus”.

Setting the Dialog Message, Dialog Title, and Button Labels

In the IRIS ViewKit dialog mechanism, you set the dialog message, dialog title, and button labels using VkDialogManager member functions before posting each dialog. Because you could specify different messages, titles, and button labels when you post the dialog from different points in your program, RapidApp doesn't offer any method of setting these items. Instead, you must use the appropriate VkDialogManager member functions when you post the dialogs.

The post(), postModal(), postBlocked(), and postAndWait() functions each accept as an argument the message for the posted dialog. The setTitle() function sets the title for the posted dialog. The setButtonLabels() function sets the button labels for the posted dialog. See the VkDialogManager(3Vk) reference page and Chapter 7, “Using Dialogs in ViewKit,” in the IRIS ViewKit Programmer's Guide for more information on setting the dialog message, dialog title, and button labels.

Code Generation for Customized Standard Dialogs

When RapidApp generates code for a customized standard dialog, it creates the dialog as a subclass of the corresponding IRIS ViewKit dialog class. For example, if you customize a File Selection dialog, RapidApp creates a subclass of VkFileSelectionDialog. (See Chapter 7, “Using Dialogs in ViewKit,” in the IRIS ViewKit Programmer's Guide for more information on the IRIS ViewKit dialog classes.)

For customized standard dialogs, RapidApp creates all child elements (including the menu bar, if you've added one to the dialog) directly in the dialog subclass's createDialog() member function. RapidApp does this, rather than encapsulating the child elements in a subclass of VkComponent as it does for other windows, because when you customize a standard dialog, it's usually to add an option menu, a few toggle buttons, or some other minor addition. Encapsulating these elements in a component—and generating four extra source and header files in the process—is overkill in this case. If you add a more complex set of controls to a standard dialog, you can always explicitly encapsulate these controls in a class as described in “Creating Components”.

For customized standard dialogs, RapidApp includes in the dialog subclass the callbacks associated with all menu items, pushbuttons, and other controls that you add to your customized dialog.

How you specify the actions taken when the user clicks a standard dialog button (that is, the OK, Apply, and Cancel buttons) depends on the function you use to post the dialog. If you post the dialog using post(), postModal(), or postBlocked(), you provide a callback function for each button. If you post the dialog using postAndWait(), you test the enumerated value returned by the function and then perform an appropriate action. See “Posting Dialogs” in Chapter 7 of the IRIS ViewKit Programmer's Guide for more information on specifying actions to take when users click dialog buttons.

Code Generation for Dialogs Customized From the Dialog Window

When RapidApp generates code for a dialog customized from the Dialog Window, it creates the dialog as a subclass of VkGenericDialog. See “Deriving New Dialog Classes Using the Generic Dialog” in Chapter 7 of the IRIS ViewKit Programmer's Guide for more information on the VkGenericDialog class.

For Dialog Windows, if the child element of the customized dialog isn't a component (that is, a C++ class), RapidApp automatically encapsulates that child and its contents within a subclass of VkComponent. (See Chapter 2, “Components,” in the IRIS ViewKit Programmer's Guide for more information on the VkComponent class.) The customized dialog then simply creates an instance of this class in its createDialog() member function.


Note: RapidApp generates both a UI and a functional subclass for the child of a Dialog Window. Typically, you should edit only the subclass.

RapidApp creates the VkComponent subclass in this case (rather than simply creating the child elements directly in the createDialog() member function as it does for customized standard dialogs) because Dialog Windows usually contain palettes or other complex controls typical of support windows. In these cases, it makes sense to follow the same encapsulation scheme used by the Simple Window and VkWindow components.

For customized Dialog Windows, RapidApp includes the callbacks associated with all menu items, pushbuttons, and other controls that you add to your customized dialog in the VkComponent subclass it generates to contain the child elements of the dialog.

How you specify the actions taken when the user clicks a standard dialog button (that is, the OK, Apply, and Cancel buttons) depends on the function you use to post the dialog. If you post the dialog using post(), postModal(), or postBlocked(), you provide a callback function for each button. If you post the dialog using postAndWait(), you test the enumerated value returned by the function and then perform an appropriate action. See “Posting Dialogs” in Chapter 7 of the IRIS ViewKit Programmer's Guide for more information on specifying actions to take when users click dialog buttons.

RapidApp also generates ok(), cancel(), and apply() functions in the dialog subclass. The default actions of these functions are to call their corresponding VkDialogManager functions, which dismiss your dialog whenever the user clicks on either the OK or Cancel button, and keeps the dialog posted whenever the user clicks on the Apply button. You can change this behavior by editing these functions in your dialog subclass. You can also include in them any other code needed to support your custom dialog (for example, storing the values of various controls in class data members that you can then retrieve using access functions that you provide for your class).

Example of a Custom Dialog

Figure 6-25 shows an example of a custom dialog created from the Dialog Window. In this case, when you generate code, the container widget containing the scale and label is encapsulated into a subclass of VkComponent. Alternatively, you could select the container widget and explicitly create a component, VolumeControl for example, before generating code.

Figure 6-25. Example of a Custom Dialog


When RapidApp generates the code for the dialog's child class, it adds three member functions to it: ok(), cancel(), and apply(). These functions are called when the user clicks the corresponding button. You can add code to these functions to perform whatever tasks you require. In the case of the custom dialog shown in Figure 6-25, the VolumeControl::ok() function can store the current value of the scale widget into a data member; the VolumeControl::cancel() function can restore the scale to the previously stored value.

Because a custom dialog is a subclass of VkGenericDialog, you post, dismiss, and set dialog titles and button labels the same way as for any other IRIS ViewKit dialog. For example, if the name of the dialog class for the dialog shown in Figure 6-25 is VolumeDialog, you create an instance of the dialog in your program with:

VolumeDialog _volumeDialog = new VolumeDialog();

Then you post this dialog with a call such as:

_volumeDialog->post();

See Chapter 7, “Using Dialogs in ViewKit,” in the IRIS ViewKit Programmer's Guide for more information on manipulating dialogs in IRIS ViewKit.

If you want to retrieve values set in the dialog or otherwise manipulate the dialog, create these access functions in both the dialog class and the child class. The dialog class should simply call the corresponding function in the child class. For example, assume that you want to be able to retrieve the last value of the scale in the dialog shown in Figure 6-25. Assume also that the dialog's child class, VolumeControl, stores the value in a private data member, _scaleValue. First, add the following function to the VolumeDialog class:

// _volumeControl contains a pointer to the child
// VolumeControl object.

int VolumeDialog::getValue()
{
    return ( _volumeControl->getValue() );
}

Next, add the following function to the VolumeControl class:

int VolumeControl::getValue()
{
    return ( _scaleValue );
}

Finally, retrieve the value from the dialog with:

currentValue = _volumeDialog->getValue();

Work With User-Defined Components

An important concept in RapidApp is creating self-contained components—C++ gui classes—that you can then reuse not only in the application you're currently building, but in other applications as well. This section describes how to create and edit components in RapidApp. See Chapter 8, “Component Libraries,” for information on how to create and use libraries of components that you can reuse in other applications and distribute to other developers.

Creating Components

It's easy to create components in RapidApp.

  1. Select the container that you want to be the top-level element in your component

  2. From the Classes menu, choose “Make Class.”

    RapidApp displays a dialog prompting you for the name of your new class, as show in Figure 6-26.

    Figure 6-26. Make Class Dialog


  3. Determine which class the component should be derived from.

    By default, RapidApp creates your component as a subclass of the IRIS ViewKit VkComponent class. If you want to handle ToolTalk messages with your component, choose the IRIS ViewKit VkMsgComponent option.

    You can also include your own super class in this option menu. For information on how to do this, see “Deriving From Your Own Super Class”.


    Note: To handle ToolTalk messages, you also need to select “Preferences” from the File menu, go to the RapidApp card, and set the Message system to “ToolTalk.” This causes RapidApp to instantiate a VkMsgApp object instead of a VkApp object. See Appendix A, “ViewKit Interprocess Message Facility,” in the IRIS ViewKit Programmer's Guide for more information on the VkMsgApp class and the IRIS ViewKit support for ToolTalk.


  4. Keep or change the Class Name.

  5. Set or unset the “Add support for dynamic loading” option.

    RapidApp allows you to create components that can be loaded back onto the RapidApp palette as first class objects. To support this, RapidApp adds two simple functions to each class, to allow them to be dynamically loaded.


    Note: This option is set by default for non-window components and meaningless for SimpleWindow, VkWindow, and dialog classes.To globally set this option, go to the Code Style card in the Preferences dialog and set the “Add support for dynamic loading” option.


  6. Set or unset the “Split into UI/Derived” option.

    As discussed in “Class Architecture”, by default, RapidApp generates two separate C++ classes. One class, which usually has the suffix UI appended to the class name, contains all the code needed to generate the user interface, including creating components and IRIS IM widgets, registering callbacks, and so on. The second generated class is a subclass of the UI class and contains the code that implements the actual functionality of the component. If you use this approach, when you add the functional code to your component, you only need to do so in the derived class.


    Note: This option is set by default for non-window components and isn't meaningful for SimpleWindow, VkWindow, and dialog classes. To globally set this option, go to the Code Style card in the Preferences dialog and set the “Split classes into UI/Derived” option.


  7. Click OK.

After creating the new class, RapidApp adds its representing icon to the User-Defined palette. (RapidApp creates the palette if it doesn't already exist.)

An Example: Creating a Component

As an example of creating a component, consider the calculator program created in Chapter 1, “RapidApp Tour.”. You can encapsulate the calculator interface in a self-contained Calculator component so that you can reuse it elsewhere. To do so:

  1. Open the file calc.uil in RapidApp.

    If RapidApp is running, select “Open” from the File menu, then select calc.uil from the file dialog that appears. If RapidApp isn't running, you can drag the calc.uil file onto the RapidApp icon, double click on the calc.uil icon, or change into the Calc directory and enter:

    % rapidapp calc.uil 
    

  2. Select the Bulletin Board container by clicking the background area of the calculator window.

  3. Create a Calculator class by selecting “Make Class” from the Classes menu. Type “Calculator” in the prompt window that appears, as shown in Figure 6-27.

    Figure 6-27. Creating a Calculator Class


    RapidApp updates the resource editor area and header area to display information about the Calculator class that you created. The header information is shown in Figure 6-28.

    Figure 6-28. Class Header


    RapidApp also creates a new palette named “User-Defined” (if it didn't already exist). If you select that palette, you'll notice it contains a new icon named “Calculator,” as shown in Figure 6-29. You can now create additional instances of the Calculator component just as you would any other interface element.

    Figure 6-29. Calculator Icon from User-Defined Palette


  4. Generate Code.

    If you generate code now, RapidApp creates a CalculatorUI and Calculator class. It no longer generates a BulletinBoard class as it did before because the top-level element in the window is already a class—Calculator. Because Calculator is a new class, RapidApp can't merge the code changes you had previously made to implement the calculator functionality; that code is in the BulletinBoard.C file. You need to copy your changes from BulletinBoard.C to Calculator.C. RapidApp automatically updates the rest of your application to use the Calculator class rather than the BulletinBoardClass class.

Deriving From Your Own Super Class

You can provide your own classes to be used as super classes for simple components, normally subclasses of VkComponent, and windows, which can be subclasses of VkWindow or VkSimpleWindow. You cannot currently define super classes for Dialogs. There are several restrictions:

  • Your class must be derived directly, or indirectly from VkComponent, VkWindow, or VkSimpleWindow.

  • Your new base class must not have any UI itself. The mechanism supports extensions to the API, not visual differences.

  • The class should not be abstract, or at least be aware that if a class is abstract, classes derived from it will not be usable until you implement the pure virtual member functions.

The set of base classes available for windows without menus (derivations of VkSimpleWindow) is defined by files installed in /usr/lib/RapidApp/BaseClasses/VkSimpleWindow

The set of base classes available for windows with menus (derivations of VkWindow) is defined by files installed in /usr/lib/RapidApp/BaseClasses/VkWindow

The set of base classes available for regular components (derivations of VkComponent) is defined by files installed in /usr/lib/RapidApp/BaseClasses/VkComponent

There are also personal directories under $HOME/.rapidappdir/BaseClasses. Each of these directories contain files that provide various information about base classes. For example, the VkComponent directory contains a file VkComponent, which is the default. This file contains the following:

*VkComponent.headerFile: <Vk/VkComponent.h>
*VkComponent.library: -lvk

To add a new candidate super class that can be used instead of VkComponent, replicate this file format for your class. For example, assume you have a new class, MyComponent, defined as:

////////////////////
// MyComponent.h
class MyComponent : public VkComponent {

public:
MyComponent(const char *name);

void print();
};

Compile your class, put it in a library, such as libmyComponent.so, and put the header somewhere, perhaps /usr/include/MyStuff/MyComponent.h.

Now, create a file named MyComponent that contains

*MyComponent.headerFile: <MyStuff/MyComponent.h>
*MyCSomponent.library: -lmyComponent

and put this file in either /usr/lib/RapidApp/BaseClasses/VkComponent/MyComponent

or put it under
$HOME/.rapidappdir/BaseClasses/VkComponent.

Restart RapidApp, and the next time you create a class, you should see this class added to the list of base class choices in the popup dialog after you invoke the “Make Class” command.

A similar procedure can be used to define new classes for VkSimpleWindow or VkWindow.

Using Components

After creating a user-defined component, you can create instances of, select, move, and otherwise manipulate it just as you would any other interface element.

Editing Components

After creating a component, you can no longer simply click on one of its elements to edit it; RapidApp treats the component as a single interface element. However, you can still use RapidApp to edit the component.

To do so, toggle on “Edit Classes” in the Classes menu. RapidApp hides your current interface and displays all classes currently on the User-Defined palette. You can now select, edit, and manipulate the individual elements composing the classes. You can even add elements to and delete them from components. When you are finished editing classes, toggle off “Edit Classes.” RapidApp redisplays your current interface, reflecting the changes you made to your components.

Deleting Components

Once you create a class, it remains on the User-Defined palette even if there are no instances of the class in your interface. When you save your interface, RapidApp saves the class along with the rest of the information about the interface. If you no longer want to keep a class on the palette, you can delete it in one of two ways:

  • The first method is to “unmake” the class. To do so, create an instance of the class, select it, and then select “Unmake Class” from the Classes menu. RapidApp displays a dialog asking you if you want to remove the class from the palette. If you press OK, RapidApp removes the class; otherwise it “dismantles” the instance you have currently selected but leaves the class on the palette.

  • The second method is to toggle on “Edit Classes” in the Classes menu. RapidApp hides your current interface and displays all classes currently on the User-Defined palette. Delete any class you no longer want by deleting the top-level window for that class. RapidApp then removes the class from the palette. Toggle off “Edit Classes” when you're finished deleting classes.