A UIL module is a block of declarations and definitions for the values, procedures, literals, and objects that make up a user interface specification. Each UIL file contains either one complete module or, if the file is to be included in another UIL file, at least one complete top-level construct within a module.
Each module has the following structure:
This section discusses the components of a UIL module, but it does not describe the UIL syntax in detail. For more information, see the UIL(5X) reference page in the Motif Programmer's Reference.
Each module begins with the declaration module name. The keyword module must be in lowercase.
Several optional declarations at the beginning of the module modify characteristics of the module as a whole:
The names declaration specifies whether names in the UIL file are stored in a case-sensitive or case-insensitive way. The following declaration, the default, means that names are stored as they appear in the UIL file, and all UIL keywords must be in lowercase:
names = case_sensitive
The following declaration means that all names are stored in uppercase, and UIL keywords can be in uppercase, lowercase, or mixed case:
names = case_insensitive
The entire names declaration itself must be in lowercase, and it affects only the part of the module that follows it.
The character_set clause declares the default character set for strings and compound strings specified in the module by double quotes (" string"). If this clause is not present, UIL derives the default character set from the language environment in which the UIL file is compiled. This does not affect the character set of strings specified in the module by single quotes (' string'). UIL derives the character set of these strings from the language environment in which the UIL file is compiled. The character set in this clause must be either a keyword representing one of the character sets UIL knows about or a character set returned by the character_set function.
The objects clause specifies whether UIL should define objects of the specified types as widgets or gadgets. For example, this declaration specifies that UIL should define objects of type XmPushButton to be gadgets:
objects = { XmPushButton = gadget; }
A declaration for an individual object can override this specification.
The include directive includes the contents of a file in the current module. The directive consists of the keywords include file followed by a string representing the filename. If the filename has a full directory specification, UIL searches that directory for the file. Otherwise, UIL searches the directory of the main UIL source file and then the directory of the current UIL source file. The -I option to the uil command adds a directory to the search list.
Included files are useful for definitions common to more than one UIL module. In conjunction with the -I option to uil, they are also useful in internationalizing applications. Localized definitions for strings, font lists, and the like can reside in files included from different directories depending on language environment. In this case, the include directives should not specify the directories; instead, you can use the -I option to uil to compile files for different language environments without editing or duplicating UIL files.
The value clause defines one or more names and associates them with values. The names can stand for values elsewhere in the module.
The specification for each value is either a literal expression or a call to a UIL function that generates a value. Each value has a UIL type that depends on the representation of the literal or the type of value returned by the UIL function. For more information on UIL types, literals, and functions, see the UIL(5X) reference page in the Motif Programmer's Reference.
By default, the names and their associated values are private to the module. The value declaration can also export a value to other modules or import a value from another module. For each name declared to be imported, MRM assigns the value from the corresponding exported declaration at run time.
In this example, the value id_1 is exported:
value id_1: exported 1; label_1: compound_string('Off');
Another module can use the value id_1 as follows:
value id_1: imported integer;
An identifier clause declares one or more names that can appear elsewhere in the module. At run time, MRM assigns values to these names from data defined in the application program. The application uses the MrmRegisterNames or MrmRegisterNamesInHierarchy routine to establish the correspondence between UIL identifier names and application-defined data. The UIL compiler performs no type checking on identifiers.
The following example identifies names for x and y values that the application defines at run time:
identifier app_x_value; app_y_value;
A procedure clause declares names of callback procedures or of creation routines for user-defined widgets. The application program itself defines the actual procedures. As with identifiers, the application must use MrmRegisterNames or MrmRegisterNamesInHierarchy to associate the procedure names with the actual procedures at run time.
For a callback procedure, the procedure declaration can also specify the type of data represented by the second argument (the application data pointer) to the callback routine:
procedure toggle_cb (integer); push_button_cb (integer);
An object clause defines a widget or gadget and assigns a name that can stand for the object elsewhere in the UIL module. As with values, an object definition by default is private to the UIL module, but the object clause can declare it to be exported or imported. In addition to the UIL name, the object clause specifies the object's type and a list (enclosed in braces) that can define children, initial resource values, and callback procedures.
The object type specification is a keyword that is usually the same as the name of the corresponding toolkit widget class. For example, the type keyword for a MainWindow is XmMainWindow and for a PushButton is XmPushButton. UIL also allows type specifications that correspond to toolkit convenience routines for creating some kinds of specialized widgets, including menus, dialogs, ScrolledList, and ScrolledText. For example, the keyword XmPulldownMenu specifies a PulldownMenu, and the keyword XmPromptDialog specifies a PromptDialog.
The object clause can also specify that the object is to be either a widget or a gadget, overriding the default specified by the objects clause. For example, the following defines a PushButtonGadget:
object pb: XmPushButton gadget {};
Alternately, an object clause can specify a gadget by using the gadget class name (for example, XmPushButtonGadget) as the type specification.
An object clause can specify the children of a composite widget. This specification appears inside the object list section and consists of the keyword controls followed by a list of child declarations. The declaration for each child consists of an object type and, usually, a name that refers to the definition for the child widget in its own object clause. Instead of a name for the child, the declaration can contain an entire local definition for the child widget in the form of an object list section. The child declaration can optionally begin with the keyword managed or unmanaged, which specifies whether or not MRM should manage the child after creating it. The default is to manage the child.
Some manager widgets automatically create children. For example, MainWindow creates three separators to separate its main components. The controls list can contain declarations for these children so that the UIL file can specify resource values for them. The declaration for an automatically created child begins with a specification of the name of the child, formed by prepending Xm_ to the actual name of the child widget. The names of automatically created children are documented in the reference pages for the manager widgets in the Motif Programmer's Reference.
Following is an example of specifications for child widgets:
object main_win: XmMainWindow { controls { XmMenuBar main_menu; Xm_Separator1 { arguments { XmNseparatorType = XmSHADOW_ETCHED_OUT; XmNmargin = 5; }; }; XmScrolledText text_win; }; };
In general, a child widget can be of any type the Motif toolkit allows for a child of the parent widget. In some cases, the type of the child differs from the Motif toolkit class. For example, dialogs and menus require shells as their parents, but in UIL a dialog or menu is declared to be a direct child of its parent, with no intervening shell. MRM creates the shell at run time. In this way, UIL and MRM act like the Motif convenience routines for creating dialogs and menus.
Some widget hierarchies in UIL are slightly different from the corresponding hierarchies in the toolkit. For example, in UIL a PulldownMenu in an OptionMenu is described as a child of the OptionMenu, not of the OptionMenu's parent as it is in the toolkit. In a PulldownMenu system from a MenuBar or a PopupMenu, each PulldownMenu is a child of the associated CascadeButton, not of the CascadeButton's parent as it is in the toolkit. For more information, see Chapter 6.
An object clause can specify resource values for MRM to pass to the widget's creation function. This specification appears inside the object list section and consists of the keyword arguments followed by a list of resource declarations. The declaration for each resource consists of the name of the resource as in the toolkit (for example, XmNheight) followed by = (equals sign) and a value for the resource. The type of the value must be of the proper UIL type for that resource. For information on the required UIL type for each resource, please refer to the Motif Programmer's Reference.
Following is an example of specifications for initial resource values:
object main_win: XmScrolledText { arguments { XmNrows = 10; XmNwordWrap = true; XmNbackground = color('red'); }; };
In some cases, UIL provides a value for a resource related to a resource that appears in a specification. For example, if a specification contains a value for XmNitems in a List, UIL provides the appropriate value for XmNitemCount. For resources of type, dimension, or position, you can specify units by using the syntax described in the XmNunitType resource of the XmPrimitive reference page.
An object clause can specify procedures to appear in callback lists for the object. This specification appears inside the object list section and consists of the keyword callbacks followed by a list of callback list declarations. The declaration for each callback list consists of the name of the callback resource as in the toolkit (for example, XmNactivateCallback) followed by = (equals sign) and a value specification for the resource.
In addition to appropriate toolkit resources, the specification can include the special callback list name MrmNcreateCallback. MRM invokes callback procedures on this list when it creates the widget. These procedures provide a means for the application to identify the widget ID of a widget created by MRM.
The value specification can be one of two forms:
The UIL compiler issues a warning if a procedure specification contains an application data argument whose type does not match the argument type in the corresponding procedure declaration.
The application uses the MrmRegisterNames routine or the MrmRegisterNamesInHierarchy routine to establish the correspondence between UIL procedure names and the application-defined procedures.
Following is an example of specifications for a callback list:
object pb: XmPushButton { callbacks { XmNactivateCallback = procedure pb_activate_cb (pb_ident); }; };
A list clause defines one or more lists of specifications for resources, callbacks, procedures, or widget children. Each list has a symbolic name that the application can use to refer to the list elsewhere in the UIL file, usually in an object declaration. The main use for this clause is to define lists of specifications that are common to more than one object definition.
A list clause consists of the keyword list followed by one or more list specifications. Each list specification contains the name, type, and contents of the list. Following are the four kinds of lists:
In each case, the form of the list is the same as that of the corresponding clause of an object declaration.
Following is an example of a list declaration:
list pb_activate_procs: procedures { pb_ac_proc_1 (); pb_ac_proc_2 (); }; list pb_callbacks: callbacks { XmNactivateCallback = pb_activate_procs; XmNarmCallback = procedure pb_arm_proc (); }; list pb_args: arguments { XmNheight = 10; XmNbackground = color('red'); }; object pb_1: XmPushButton { arguments { arguments pb_args; XmNlabelString = pb_label_1; }; callbacks pb_callbacks; }; object pb_2: XmPushButton { arguments { arguments pb_args; XmNlabelString = pb_label_2; }; callbacks pb_callbacks; }; list menu_items: controls { XmPushButton pb_1; XmPushButton pb_2; }; object menu_1: XmPulldownMenu { controls menu_items; };
Each UIL module must end with an end module clause.