27.2.1 Using Separate Modules
When an application uses multiple top−level windows, such as a main window and various dialog boxes, it makes
sense to describe each window in a separate UIL module. When a window is especially complex, you may want to
describe the interface using several modules. For example, the menu system of an application could be described in a
separate module, as illustrated by the example in Chapter 25, Building an Application With UIL.
When you divide an application into separate modules, it is easier to find specific declarations or definitions because
the modules map directly to the appearance of the interface. Multiple files also help to reduce editing conflicts when
you are working on a project with a team of programmers. Breaking components into separate files helps to eliminate
dependencies between logically separate parts of the interface. For example, if you make a change to a dialog, it
shouldn't affect any other parts of the interface. Another benefit is rapid prototyping and testing. With a few
modifications, you can use the showuid program from Chapter 24, Creating a User Interface With UIL, to preview a
component without needing to have a complete application program. We'll take a closer look at prototyping a user
interface later in this chapter.
27.2.2 Organizing Within a Module
Within a UIL module, one organizational decision involves whether widgets are declared from the top−down or from
the bottom−up. Top−down organization means that you define the parent widgets first, followed by their children.
Bottom−up is the opposite, in that you define the child widgets and then define their parents. We recommend using
the top−down approach, since it is an extension of the organization at the file level. In addition, it is more natural for
developers who are accustomed to creating an interface in application code. Whichever approach you choose, you
should be sure to use it consistently in all of your modules.
Using value and list sections to define settings for widget resources that you use or change often is another useful
practice. This technique makes a module easier to read and maintain. As you know, UIL lets you define variables that
can be fetched by an application. It makes sense to place values that you intend to fetch in the same module as the part
of the interface to which they correspond. Although UIL allows forward references to most variables, you should try
to define or declare variables before using them, as it is a more familiar style. Grouping variables together at the
beginning of a module is another common practice that we recommend.
In some cases, you may need to share a variable or a list among several modules. For most types of variables, you can
place the definition in one module and include declarations in any other modules that use the value. For lists and for
values that cannot be exported, you must place the values directly in an include file. This kind of reuse frees you from
trying to maintain the same information in more than one place.
27.2.3 Supporting Internationalization
Although it is a good idea to put variable definitions in the module where you use them, we need to make an exception
to this guideline for internationalization purposes. To support internationalization, an application should not use literal
values for strings, compound strings, character sets, fonts, and font sets in a UIL module that contains widget
declarations. You should consolidate these values into one module per language and define a variable for each value.
Then, you can use the variables in widget declarations instead of literal values. You can create a single include file
that contains declarations of all of these values and include it anywhere you need to use one of the values. the source
code illustrates this -technique.
! i18n_dialog.uil − Dialog used to prompt the user for a filename
module savebox
27 Advanced UIL Programming 27.2.1 Using Separate Modules
725
include file 'strings.uih';
object root : XmPromptDialog {
arguments {
XmNokLabelString = ok_text;
XmNcancelLabelString = cancel_text;
XmNhelpLabelString = help_text;
XmNselectionLabelString = save_prompt_text;
XmNdialogTitle = save_title_text;
};
};
end module;
As you can see, a variable is used everywhere that we needed to set a language−dependent resource string. the source
code shows the corresponding strings.uih declaration file.
! strings.uih − Interface string declarations
value
ok_text : imported compound_string;
cancel_text : imported compound_string;
help_text : imported compound_string;
save_title_text : imported compound_string;
save_prompt_text : imported compound_string;
The declaration file is the same for every module that uses the strings, so you don't have to declare them in each
module. Each string variable is declared as an imported value, which we explained in Section #suilshare. All you
need is a string definition file for each language that is supported by the application. the source code contains the
English version of the strings for this dialog.
! strings.uil − English version of interface strings
module strings
value
ok_text : exported compound_string ("Ok");
cancel_text : exported compound_string ("Cancel");
help_text : exported compound_string ("Help");
save_title_text : exported compound_string ("Save Dialog");
save_prompt_text : exported compound_string ("File Name:");
end module;
To support another language, we only need to create a new version of strings.uil for that language. The English
version of the dialog is shown in the figure.
27 Advanced UIL Programming 27.2.1 Using Separate Modules
726
Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.