8. The Gilt Interface Builder

The Gilt Interface Builder allows dialog boxes and other windows to be created interactively using the mouse. Widgets, such as scroll bars, buttons, and text input fields can be placed with the mouse, and properties set. Then, Gilt will generate C++ code to generate the same window at run time.

8.1 Acknowledgments

The Gilt interface builder is based on the AmEdit tool created by S. Nebel from Linkworks Ltd, Wellington NZ.

8.2 Introduction

The Gilt Interface Builder allows widgets, like scrollbars, buttons, and text input fields, to be placed into a window with the mouse, and properties can be set. You can also draw rectangles, lines and circles. When the design is complete, then you can save the design to a file, and generate C++ code which can then be used as part of your application. This is much faster than writing the code by hand.

We consider this version of the Gilt tool to be only just a start. There are many things we know are needed to make this a complete and comprehensive tool, but we have found the current version to be quite helpful. Let us know what is most important to work on next.

The Gilt sources are in amulet/samples/gilt/* and it can be made from the amulet/bin directory using ``make gilt'' on Unix, ``nmake gilt.exe'' on the PC, or using the gilt project on the Mac. The program amulet/samples/examples/example/example2.cc includes a dialog box created using gilt.

Gilt stands for the Graphical Interface Layout Tool.

8.3 User Interface

Hopefully, most of the user interface for Gilt is self-explanatory. Figure 1 shows a picture of Gilt editing the dialog box used for specifying the properties of the generated C++ file.

If you want to look at any of the dialog boxes used by Gilt, they are the *.sav files in the samples/gilt directory. Figure 1 is showing savecpp.sav.

The general way to use Gilt is to select a widget, or drawing primitive in the palette on the upper left, and then drag out a region for that in the main part of the window. When the palette is in ``select'' mode (with the arrow selected), then clicking on objects with the left button selects them, pressing and dragging moves them, dragging on the handles grows them, and double clicking sets their properties. Dragging in the background where there are no objects will select all the objects in the region. Multiple objects can be moved at the same time. Some objects, such as the various button panels, cannot be resized. All of the objects have a default size, so if you click on the desired object in the palette, and then click in the main window without moving, then an object of the default size will be created.

As always in Amulet, when creating, moving or growing (or typing in text into a text field), you can abort the operation by typing ^g (control-g). Of course, (almost) all operations are undoable using the Undo item in the Edit menu.

8.3.1 What can be created

The main palette contains all of the objects that currently can be created using Amulet. They are (from top to bottom, left to right):

There are many other widgets in the Amulet widget library that are not yet supported in Gilt (see the Widgets chapter).

8.3.2 Style and Font Properties

All objects are always created with the default properties defined by the prototypes. (Unlike most graphics editors, choices in the color palettes do not affect the next object drawn--you have to draw the object first, select it and then change its properties.). If an object is selected, then you can set its color and font using the palettes on the left of the Gilt window. The middle palette is for the fill color of the object. The top-left item in the menu looks white but is actually unfilled (Am_No_Style).

If no object is selected, then clicking on a color in the color palette will set the background for the window.

The group of lines is used to set the line-style. Note that you have to click pretty much exactly on top of the line. The Line style does not affect most of the widgets, but it is used for changing the color of the lines, the outlines for rectangles, circles and polygons, and the color of the text in a regular Text object. The top-left entry in the line palette is invisible and means no-line, which is sometimes useful for rectangles and circles.

The bottom palette is for changing the font used for strings. Currently, only the default (Fixed) font is supported. The rows are for the Small, Medium and Large sizes, and the columns are for Bold, Italic and Underline.

8.3.3 Other Object Properties

Each kind of object also has additional properties that can be set. These are available by solacing an object and selecting ``Properties...'' from the edit menu. A faster way to get to the properties window for an object is to double-click on it, or to click on it with the middle mouse button. For these, the object does not even have to be selected.

If you Cancel any of these dialog boxes, the changes are not made, and after you hit OK, you can later Undo the changes using the regular Undo in the Edit menu.

All objects have a Name property which, if supplied, is the name of the slot the object is put in (see Section 8.4.2).

The Label property is used to change the string displayed for text objects, and also the label for buttons and text and number input fields.

All of the panel widgets (like button panels, radio buttons, checkboxes, etc.) have a large set of properties. The name of the widget is at the top, and then the list of current labels of all the values. Selecting a name will let it be deleted (``Delete Item'') or its string edited (typing RETURN or hitting ``Update Item'' confirms the change), and a new item can be added by typing the new label and hitting ``New Item''. Note that this interface only supports putting text items into the labels. You might instead want to use the built-in command objects (see Section 7.4 in the Widgets chapter). Also, you might want to use a graphical object or a group as a label. Whereas these are easy to do by writing code in Amulet, Gilt does not provide an interface to this yet. The OK-Cancel buttons will not allow you to change their labels or add new ones.

Also for panels, you can control various properties of the layout of the buttons. If ``Vertical Layout'' is selected, then the buttons will be up-and-down, and if it is not selected, then the buttons will be across (horizontal). (This button selects whether the Am_LAYOUT field of the widget will contain Am_Vertical_Layout or Am_Horizontal_Layout). The ``Box on Left'' button is used for radio buttons and check boxes and tells which side of the label the box is on. If ``Fixed Width'' is selected, then all the buttons are the same width, otherwise not (this might be important if they are not vertical). The Horizontal and Vertical Spacing between Items can be adjusted either bigger or smaller to control how far apart the items in the panel are. If you want multiple rows and columns, you can specify the Maximum Number of Items in a Row or Column.

For a Number Input widget, you can specify whether the values that can be specified should be restricted to a range of values, and if so, what the minimum and maximum values are.

The Border rectangle under the Motif look-and-feel can look ``Selected'' (pushed in). In the Windows and Macintosh Look-And-Feel, this button has no effect on the appearance of the widget.

For scroll groups, you can specify the size of the scrollable region (``Inner Width and Height''), whether the Vertical and Horizontal scroll bars are displayed at all or not, and which side of the group the scroll bars are on.

8.3.4 Commands in the Menus

The accelerators for each of these are displayed in the menus. Most of these use the built-in command objects without change (see Section 7.4 in the Widgets chapter).

8.4 Using the Objects with an Application

Gilt generates fairly simple C++ code for the specified objects. The file creates a group or window with a name specified by the programmer in the Generate C++ dialog box (see next section). This main group or window will have all of the drawn objects as parts. If the part was given a name using the ``Name for item'' field of the property sheet for the object, then that name is used for the part. For example, suppose that a text field was added to the window, and the ``Name for Item'' for the text input widget is ``foo''. Then, the window will have a slot named foo that will contain the text input widget.

Gilt is set up to allow the generated dialog boxes to be used by accessing and setting the values of the widgets in them. The generated C++ file is not intended to be the main program. You should have a different file with main() in it, and link the generated file to it. Gilt will generate a header file to be used to connect them.

See samples/examples/example2.cc for an example of using a Gilt-generated dialog box. You can load the dialog box into Gilt by loading example2db.sav and you can see the generated C++ and header files as example2db.cc and example2db.h.

The typical way to use a Gilt-generated dialog box called ``MyDB'' with a widget named ``FOO'' is:

Gilt is not set up to specify call-backs (or Am_DO_METHODs) with widgets. If you want a widget to have a custom command or a Am_DO_METHOD, you will have to edit the generated C++ code. For example, if Gilt generated the following code, you could hand-edit the code to add the my_do_method line shown in bold:

    .Add_Part(GOFORITBUTTON, Am_Button.Create()
      .Set(Am_LEFT, 94)
      .Set(Am_TOP, 69)
      .Set(Am_WIDTH, 66)
      .Set(Am_HEIGHT, 40)
      .Set(Am_FILL_STYLE, Am_Amulet_Purple)
      .Get_Object(Am_COMMAND)
        .Set(Am_LABEL, ``Go For It'')
        .Set(Am_DO_METHOD, my_do_method)  //added by hand-editing
        .Get_Owner()
    )

8.4.1 The ``Generate C++'' dialog box

The defaults for the name fields are generated from the name of the file last saved or opened. If all the fields are blank (due to not having saved to a file, or because the ``Clear All'' button at the bottom is hit), then filling in the ``Name of Main Object'' field will fill in default values for the other fields.

There are lots of options when saving the C++ file. The main window or object must be given a name. This will be used as the name of a global C++ variable that holds the prototype for the object. The initialization procedure will be called that name with ``_Initialize'' appended.

The filename for the C++ file is specified next. If you don't specify an extension, then Gilt will append ``.cc'' (on all platforms--so if you are on a PC and want a ``.cpp'' extension, just specify the full filename including an extension).

Normally, you will also want a header file that can be #included into your application. You might not want a header file if you have exactly one file in your application and you include the generated C++ file directly in your C++ file.

Gilt can either generate the dialog box as a window or you can create a group instead. If you make a group, then you can put instances of it inside a different group or window. If you create a window, you can pop it up with Am_Pop_Up_Window_And_Wait or just by making it Am_VISIBLE on the screen. The window's title can be specified, and whether it should be fixed size or not.

Next, you can specify the size that the window or group should be. The default is to use the formulas Am_Width_Of_Parts and Am_Height_Of_Parts so the window be just as big as the contents. The other alternative is to explicitly set the size. The default values for the Width and Height are the current size of the Gilt window, so it is a good idea to resize the Gilt window so it shows the window the size you want to see it at run-time before issuing the Generate C++ command.

The Clear All button clears all the values in the Generate C++ dialog box, in case the default values generated by the system are not useful. OK generates the file, and Cancel gets rid of the dialog box without doing anything.

8.4.2 Slot and Object Names

The names given to objects are used as slot names for the object as part of the main group or window. Therefore, the names should be valid as part names. Gilt helps with this by substituting underscores ``_'' for any character found in the name that isn't legal as a C++ variable name.

In the header file, Gilt generates a define for the slot name, and in the C++ file, Gilt generates a Am_Register_Slot_Name call for the slot name.

8.4.3 Creating the Dialog Box or Group

Don't forget to call the Initialize procedure before trying to access the object. This sets the global variable with a prototype of the dialog box or group. If you only need one, then you can use this directly. If you may need more than one, then the global variable can be used as a prototype from which copies or instances can be made.

8.4.4 Setting and Accessing the Values of Widgets

All of the widgets that have names can be easily accessed by getting them out of the top-level object's named slots. Since all widget's values are available in the Am_VALUE slot of the widget, it is easy to set and access the values. For example, the following is the code used for a dialog box called Name_And_Label_Window which has two text input widgets in slots NAME_OBJ and LABEL_OBJ. The customize_text method below is the Am_DO_METHOD of a command, and it sets up the command so it is undoable.

Am_Define_Method(Am_Customize_Object_Method, void, customize_text,
(Am_Object &cmd, Am_Object &owner)) {
Am_String ls = owner.Get(Am_TEXT);
Am_String vs = owner.Get(Lw_NAME);
Name_And_Label_Window.Get_Object(NAME_OBJ).Set(Am_VALUE, vs);
Name_And_Label_Window.Get_Object(LABEL_OBJ).Set(Am_VALUE, ls);
Am_Value ok;
Am_Pop_Up_Window_And_Wait(Name_And_Label_Window, ok, true);
if (ok.Valid()) {
Am_String new_vs = Name_And_Label_Window.Get_Object(NAME_OBJ)
.Get(Am_VALUE);
    fix_lw_name(new_vs);
    owner.Set(Lw_NAME, new_vs);
    Am_String new_ls=Name_And_Label_Window.Get_Object(LABEL_OBJ)
.Get(Am_VALUE);
    owner.Set(Am_TEXT, new_ls);
    cmd.Set(Am_OBJECT_MODIFIED, owner);
    cmd.Set(Am_SLOTS_TO_SAVE, Am_Value_List().Add(Lw_NAME).Add(Am_TEXT),
	  		  Am_OK_IF_NOT_THERE);
    cmd.Set(Am_OLD_VALUE, Am_Value_List().Add(vs).Add(ls));
    cmd.Set(Am_VALUE, Am_Value_List().Add(new_vs).Add(new_ls));
  }
  else Am_Abort_Widget(cmd); //keep out of undo history
}
Other properties of the widgets, such as their color, labels or whether they are visible or not, could also be set by the program, if desired.

8.4.5 Editing the Generated C++ and Header Files

Since Gilt cannot read the Generated C++ code back in, it is important that you not hand-edit the C++ file or header file, or these changes will be lost if you need to regenerate the dialog box. The intention is that you will Save the objects as a Gilt file (using Save or Save As) and then Generate the C++ file. If any changes are needed, then load in the Gilt file and edit it interactive using Gilt and Generate the C++ file again. The interface to the generated objects is designed so that you can do it all from your main program, and not have to edit the generated file at all.

The generated C++ file and header file are just plain text and are quite readable, so you can edit them if you really want to, but remember that all hand-edits will have to be done again if you generate the C++ file again.


Last Modified: 01:48pm EDT, August 13, 1997