CCP4 web logo CCP4i: Graphical User Interface
Documentation for Programmers
The Task Window File

next button previous button top button

Introduction

The Procedures and Arrays in a Task Window File

Windows and Widgets

The CCP4i Library Commands to Draw Windows

Menus
Menu Data Types
Defining a Menu
Variable Menus

Extending Frames and Toggle Frames

Parameters Used by the Project Database

Handling of MTZ Column Labels
The taskname_run Procedure

Introduction

A task window file defines the appearance of a task window. The file is written in the Tcl scripting language but all essential functionality is provided by a small library of CCP4i commands so, at least for simpler interfaces, the programmer needs only minimal knowledge of Tcl. There is an example task window file $CCP4I_top/tasks/demo.tcl which will be referred to below.

If you are not familiar with Tcl, you should look at the Introduction to Tcl. You should perhaps read quickly through this before looking at the demo file and then refer back when features of the demo need some explanation.

The Procedures and Arrays in a Task Window File

For a task called taskname (as defined in the modules file) there must be a file called taskname.tcl in the directory $CCP4I_top/tasks. This file must define a procedure taskname_task_window which contains the definition of the graphical interface to the task. This procedure will be called when the user selects the task from the menu in the main CCP4i window. The file can also contain two other procedures:

taskname_setup
which is called prior to taskname_task_window. This can be used to perform any initialisation and is particularly used for defining menus
taskname_run
is also optional and will be called when the user picks the Run button on the task window. It can be used to do any checking and 'tidying up' of parameters before running the task.

The taskname.tcl file is not read until the user selects to run the task and then the three procedures described above are called automatically by the core (i.e. the main part) of CCP4i when required. Most of the functionality of these procedures is achieved by calls to the library of CCP4i procedures so the task window file is basically providing the meat in a sandwich.

All the variables associated with one instance of a task window are saved as elements of one array. This is necessary for keeping everything together and avoiding possible clashes where, for example, two different tasks, open simultaneously, might both have a variable called RESOLUTION_MIN. The interface is implemented so that, in principle, it is possible to have two windows interfacing to the same task open simultaneously, and with each window having an independent set of parameters which are stored in different arrays (in practice, however, this option has been disabled to avoid confusing the user). The actual name of the array is decided by the CCP4i core before it calls any of the task procedures and the name is then passed to the procedures as an argument. In practice the name of the array is usually the same as the taskname but you should not assume this is always so.

When the name of an array is passed to a procedure, it is necessary to associate that name with a local variable using the upvar command. An example of the syntax of this, taken from the demo.tcl file:

proc demo_task_window { arrayname } {
upvar #0 $arrayname array
...
....
}

arrayname will contain the true name of the array when it is passed into the procedure. The true name of the array is substituted for $arrayname in the upvar command so that the upvar command is given the true name of the array and equivalences it to the local variable array. In the task window files that I have written, including the demo.tcl, I have always used the very generic words arrayname for the argument and array for the local variable. The important point to remember, assuming you use the same convention, is: within the procedure all references to the array should use the word array except if the name of the array is being passed on to another procedure in which case $arrayname should be used.

Within the graphical interface, the names of the parameters should be the same, or similar to, the program parameter names (assuming the program has 'sensible' parameter names!) and are commonly upper case so they stand out in scripts. So the significance of parameter names such as RESOLUTION_MIN and RESOLUTION_MAX should be obvious. Within the task window files, these names are actually used as array indices so that if you need to access these variables, they are array(RESOLUTION_MIN) and array(RESOLUTION_MAX). In practice you should not often need to access these parameters but you will just pass their names on to library routines.

Windows and Widgets

Tk is the part of the Tcl/Tk package responsible for the graphics. Programming a task window does not require direct use of Tk - the CCP4i command library provides higher level functionality.

Each graphical element in Tk is called a widget. Tk has an hierarchical arrangement of widgets - a child widget (i.e. one that is the next layer down in the hierarchy) is drawn within its parent. For example, a very simplified view of the hierarchy for a task window is:

task window -> frame/folder -> line -> labels and input widgets

If you look at the task window it is horizontally partitioned into 'frames' (i.e. protocol frame and files frame) and folders and these frames are, fairly obviously, defined in terms of lines. This layout isn not inherent in Tk but is built into the CCP4i command library. The CreateTaskWindow command is used to create a window with the conventional format. The OpenFolder command is used to specify where the definition of a folder begins. The CreateLine command is used to define an entire line in the window and its arguments include the definition of the labels and input widgets on that line.

In Tk each widget has an id which is formatted rather like the format for directories in UNIX, except that a '.' is used as a separator instead of a '/'. In UNIX the root directory is '/' and in Tk the main widow of an application is named '.'. A child widget of '.' would be .foo. A child of .foo would be .foo.bar and so on.

In CCP4i the task windows usually have names .taskname. Because of the complexities of setting up scroll bars, message lines and toggleable frames (all dealt with by the CreateTaskWindow command), the components of the task window have lengthy, complex names. The programmer does not usually need to be concerned with these, but the commands which create frames and lines do return the id for the frame or line which a programmer would need to customise the interface using Tk commands directly.

The CCP4i Library Commands to Draw Windows

To follow this section, look for examples of the library commands described below in the file $CCP4I_top/tasks/demo.tcl and look at the demo task window. The library commands are described more fully in the command documentation.

An important feature of every task window is the partitioning into frames and folders. Ideally the protocol frame at the top of the window presents the user with easy to understand options to specify exactly want they want to achieve. The file frame requires the user to select input and output files and select column labels from MTZ files. Each subsequent folder contains closely related options and the folder has a title indicating the contents of the folder. Folders which contain less frequently required options are closed. I try to work towards a convention of putting 'compulsory' options in the first folder and having all other folders closed - this is not always possible.

To open a task window requires the command CreateTaskWindow - the arguments to this command include the title and icon name for the window. The command also requires an id for the window - this is usually .taskname and the name of the array which contains the parameters for this task. The name of the array is saved by the library and used by other commands such as CreateLine.

The titles of the folders within the task window are specified by the fourth argument to CreateTaskWindow. All task windows are drawn with a protocol and a file frame - the additional folders are optional. To begin the definition of the contents of each frame/folder you must call OpenFolder with the argument 'protocol' or 'file' or an integer in the range 1 to n where n is the number of folders defined using the CreateTaskWindow command. It is not necessary to call OpenFolder for the folders in the order they appear in the window so reordering the folders in a window can be done without moving around large chunks of code.

The OpenFolder command has three possible optional commands to control the default visibility of a folder:

open
the title line and contents of the folder are visible
closed
the title line of the folder is displayed but the contents are not displayed. The user can access the contents using the toggle button on the title line
hide
neither the title line nor the contents are displayed

The visibility status can be dependent on a control parameter which would usually be an option in the protocol frame.

There are several commands which draw a single line within a folder. The most generic command is CreateLine. The CreateInputFileLine and CreateOutputFileLine commands draw a line for the user to select a file. The CreateLabin command draws a line for the user to select an MTZ label. All of these commands have arguments which are the names of parameters. Each parameter must be defined in the .def file. It is a common mistake for a parameter to be missing from the .def file and an error message will appear in the report window of the CCP4i main window (hint: watch this window when you are testing a new interface!) and the line will not be drawn completely.

The 'line' routines will draw the appropriate widget for the user to select or enter a value for the parameter. As explained above, all the parameters for one task interface are stored in one array so commands such as CreateLine are actually drawing widgets which are associated with an array variable such as array(PARAM) but you do not need to be concerned about this - you just need to give the parameter name PARAM as an argument to the command.

The CreateLine command has a very flexible argument list. Usually arguments come in pairs; each pair is a keyword followed by another keyword-specific argument. For example the keyword label is followed by the text which is to appear as a label on the line. The keyword widget is followed by the name of a parameter. The appropriate widget (menu or entry field or toggle button) will be drawn for the type of the parameter which must have been defined in the taskname.def file. The CreateLine command can have a variable number of keyword arguments so the line seen by the user can be made up of any combination of label text and input widgets. The labels and widgets are drawn from left to right in the order of the keywords in the argument list. CreateLine also has other keywords which define the target for help and the help message line associated with the subsequent widgets in the line.

It is also possible to control the visibility of individual lines. CreateLine has a keyword toggle_display and the other 'line' commands have an optional argument -toggle_display which can make the display of the line dependent on some control parameter. It is not possible to control the visibility of individual labels and widgets in a line. Instead you should define the alternative forms of the line by multiple calls to CreateLine and use the toggle_display keyword to control the visibility of each instance of the line.

If you want to group together more than one consecutive lines and control their visiblity collectively, then use the OpenSubFrame and CloseSubFrame commands to group the lines together. The OpenSubFrame command has similar arguments to OpenFolder to define visibility. It is recommended to use these sub-frames wherever possible, because it makes for faster and smoother updating of a window.

It is very strongly recommended that you use the tools to control visiblity to ensure that once the user has entered what they want to do within the protocol frame, they are only faced with relevant options. A convention which I aim towards is that the visibility of a line can only be altered by a parameter in the protocol frame or in the same folder and appearing above the line in question. Visibility of folders should only be controlled by parameters in the protocol frame. These conventions are intended to avoid a 'jack-in-the-box' effect for the user.

Menus

Menu Data Types

All parameters in a task interface must have a data type which is defined in the .def file. There are many generic data types (e.g. _logical, _pdb_file, _space_group) which are defined in the types.def file but some parameters are best represented in the task interface window by a menu which is specific for the particular task interface. Each menu is treated as a data type equivalent to _logical or _space_group because, like the more generic data types, it defines what appears in the task interface window and determines what the allowed input values are.

Defining a Menu

Each menu must be given a data type name. To avoid possible clashes, the name should begin with the task name. For example, in the demo task, the two menu data types are _demo_refine_type and _demo_input_phase. Note that the data type name always begins with an underscore. The parameter which has the menu data type is defined in the demo.def file with a line which has the form:

REFINE_TYPE _demo_refine_type FULL

Here REFINE_TYPE is the parameter which has the data type _demo_input_phase and its initial value is FULL.

Each menu is a separate data type but all belong to the menu class of data types. All data types of the menu class have two properties: deflist and aliaslist (I regret the choice of names but not enough to change them). The deflist is the list of options which the user will see in the task interface window. The text for each item in the deflist must be 'plain English' for the user to understand but CCP4 programs usually expect single keywords (and the CCP4i programmer may prefer to handle single keywords). So the aliaslist is a list of single word items with one item for each of the items in the deflist. The aliaslist usually consists of the program input keywords. The aliaslist is optional - if it is missing, the deflist item will be used wherever the aliaslist is expected.

Note that where the initial value of the parameter is set in the .def file, either a deflist or an aliaslist item may be used. It is usually easier to use the aliaslist item and probably safer as the text of the deflist is liable to change as you review and refine the interface.

It is possible to define menus in the types.def file but is more convenient to call the DefineMenu command in the task.tcl file. The definition must be within the procedure task_setup (as described above).

For example in the demo.tcl file a menu is defined:

DefineMenu _demo_refine_type \
[list "full refinement" "quick refinement"] \
[list FULL FAST]

The three arguments to DefineMenu are:

menu_name
_demo_refine_type
deflist
[list "full refinement" "quick refinement"]
aliaslist
[list FULL FAST]

Two features of Tcl syntax to note here are:

Variable Menus

A variable menu is one which may change as the interface is used. For example, look at the Directories&ProjectDir window (accessed by clicking the button on the top right of the CCP4i main window). In this window, as the user adds extra project directories, the menu for selecting the default project directory is extended.

This needs more documentation

Extending Frames and Toggle Frames

To understand what these are, look at examples:

Both extending frames and toggle frames have two control buttons underneath them. The button on the right, which has a context-dependent label and allows the user to open an extra frame beneath those which might already be open. And the button on the left is a menubutton with access to some simple editing functionality to delete and copy frames. Extending frames are usually just single line frames but can have more than one line. Toggle frames are usually multi-line frames which also have a title line with a toggle button which controls the display of the frame contents. Note that closing a frame does not make the contents 'go away' or switch them off!

It is possible to nest extending frames inside either other extending frames or inside toggle frames. Only one layer of nesting is allowed and it is not currently possible to have toggle frames nested within extending or toggle frames. An example is in the Cad interface. If, for one of the input files, you choose to 'Select Input Columns', an extending frame to select MTZ columns is displayed. This 'select label' extending frame is embedded within a 'select file' extending frame.

These frames are defined using the CreateExtendingFrame and CreateToggleFrame commands. It is also necessary to write a separate procedure which defines the content of each frame. Each time the user clicks the control button to open another frame, the procedure is invoked to draw the contents of the frame. The name of the procedure is an argument to CreateExtendingFrame or CreateToggleFrame. The procedure must have certain defined arguments so that some possibly useful information can be passed to the procedure. The arguments are the array name and the value of a counter which will be '1' if this is the first frame to be drawn, '2' if it is the second frame and so on. If the frame is a nested extending frame, two counters are passed to the procedure. The first counter is for the 'outer' frame and the second counter is for the nested extending frame.

Any parameter which is used inside an extending frame or toggle frame only needs to appear once in the taskname.def file. If the root of the parameter name is PARAM, the defining line in the .def file should be for PARAM,0, i.e. the root name followed by a comma and zero. I think of this as the zero'th instance of PARAM which will always contain the initial default value for PARAM so that whenever a new extending or toggle frame is opened, it will have a parameter PARAM,n which initially takes the same value as PARAM,0.

Parameter names must not contain commas. Even if Tcl/Tk can handle them, they will confuse CCP4i!

The contents of each extending or toggle frame is defined within a separate procedure which uses commands such as CreateLine. Within the procedure commands which require a parameter name as an argument (e.g. after the widget keyword in the CreateLine command) just require the root name of the parameter. Appropriate indices will be added internally.

Each extending frame and toggle frame has an index parameter which keeps count of the number of frames opened. This parameter needs to be defined in the .def file. It usually has a type _positiveint and is initialised as zero. The name of the parameter is given as an argument to the CreateExtendingFrame or CreateToggleFrame commands. The user must NOT have access to this parameter in any other part of the interface!

When the user clicks the Run button, a new script is created to run the task as an independent process. In this run script, the parameters are no longer bundled into one array. The parameters which can potentially have multiple instances because they occur in extending and toggle frames, are converted to arrays which have the form PARAM(i) or (where they are from nested extending frames) PARAM(i,j). Note that the convention for the ordering of the indices is that the second index is for the nested loop (this is the reverse of what you might expect by analogy with the Fortran convention).

Internal to CCP4i, there are alternative conventions for naming parameters which appear in extending and toggle frames. These are discussed below - you can probably skip this discussion.

Any parameter which appears in an extending or toggle frame can have multiple instances. For example, in the Cad interface there may be multiple HKLIN parameters. The obvious way to handle these would be to have an array called HKLIN with indices 1 to n where n is the number of files. But this is not possible becase HKLIN itself is the name of element of the array which contains all of the Cad parameters. So the way this is handled in the graphical part of CCP4i, is to call the parameters HKLIN,1 HKLIN,2 ... HKLN,n etc. Note that these parameter names are really the names of elements in an array so the variables are really array(HKLIN,1), array(HKLIN,2) etc. Remember the comment made earlier that Tcl arrays are not truely multidimentional; Tcl treats the comma in these array element names as just another character but CCP4i does handle such parameters differently in some circumstances.

An extended frame embedded within another frame contains parameters which need to have two indices. So for example in the Cad interface, if two labels are selected for the first file they are given parameter names: LABIN,1_1, LABIN,1_2. Note the use of an underscore to separate the two indices (I now regret not using a comma but not enough to change it). The index before the underscore is the index for the outer loop (the file) and the index after the underscore is the index for inner loop (the labels). Note that this is the reverse of the Fortran convention for indices order.

There are utility commands to parse these complex parameters: GetIndx

Parameters Used by the Project Database

Besides the parameters required to run the task, there are three parameters which should be defined for every task which will be used by the database: INPUT_FILES, OUTPUT_FILES and TITLE. These three parameters should be defined in the .def file (see the demo.def file) but only the TITLE parameter should appear on the interface. INPUT_FILES and OUTPUT_FILES are lists of the input file parameters and output file parameters respecively. For example, for a Refmac-like refinement the INPUT_FILES might be the list "HKLIN XYZIN" and the OUTPUT_FILES might be the list "HKLOUT XYZOUT". When a task is run, the database saves the names of the files stored in the variables HKLIN, XYZIN, HKLOUT and XYZOUT and so has a record of the input and output files for the task. Beware that the input and output file list often depend on the mode of running the program so that it may be necessary to update the lists in the taskname_run procedure in the task window file.

The TITLE parameter should be defined in the .def file and should appear as the first line of the protocol frame in the task window. The text from the TITLE parameter is saved in the database and written to the Job List in the main window. If the program has a TITLE keyword, it is expected to use the same parameter. The task should have a TITLE parameter even if the program does not have a TITLE keyword.

Handling of MTZ Column Labels

The taskname_run Procedure

It is not necessary to define a procedure taskname_run in a task window file but if it is defined, it will be called when the user clicks the Run button before a run script is written. Any 'tidying up' of parameters should be done in this procedure. There are several parameters which particularly might need tidying up.

INPUT_FILES and OUTPUT_FILES
CCP4i expects every task to have parameters INPUT_FILES and OUTPUT_FILES which are necessary for the project database to save the names of input and output files correctly. The input and ouput files for a task often depend on the mode of running and these parameters might need to be updated after the user has set the run mode and just before the job is actually run.
LABIN (or similar lists of MTZ column labels)
In CCP4i the LABIN parameter is usually a list of the MTZ input column label parameters. The LABIN parameter is used by the LABELLIST keyword in the command template files to generate the LABIN keyword in the program command file. The required MTZ input columns are often dependent on the mode of running the task and so the LABIN might need to be updated after the user has set the run mode and just before the job is actually run.