Tcl for CCP4i Task Interface Programming

Liz Potterton

Documentation

The place for more information is the Tcl developers site http://dev.scripts.com/doc.

The Tcl/Tk online documentation is excellent for quick reference.

You can use tclsh in command line mode to try stuff.
 

Hello World

> wish
% puts "Hello World"

puts outputs a text string to the terminal - note use of double quotes (always in Tcl).

or, using Tk graphics commands to create a widget:

% label .l -text "Hello World" -
% pack .l
%  bind .l <Button> {puts "Goodbye"; exit}

The label command creates a label widget called .l (which is a child of the default window called just . (dot)).
The pack command 'packs' this widget into the window.
The bind command attaches a command to the label widget which is activated if the mouse button is clicked.  The command script is enclosed in curly brackets and outputs a brief message and then exits from wish.
 

Tk Widgets

All of the Tk graphics part of CCP4i can be done through APIs.  But the API commands do return the id of the widgets, for example (note use of \  i.e. line continuation):

CreateLine line  \
  label "Number of refinement cycles"  \
  widget NCYCLES

The line argument returns the id for the line which might be something like:

.w_demo.main.canvas.contents.param_1.body.l9

The dots serve like backslash in file path names and
 
.w_demo  the name of the demo window
main.canvas.contents a layer which is necessary to set up the scrollable frame
param_1 the id for the first generic folder (i.e. not protocol or file) in the window
body refers to the body of the folder, rather than the title line
l9  the id of the line

Once you know the id of the line it is possible to do some direct customisation of the widgets or to create novel widgets.  This is not recommended as a regular thing.
 

Basic Syntax for Procedures

Here's a simple bit of code to define a procedure which finds the maximum of two numbers.

proc max { arg1 arg2 } {

   if { $arg1 > $arg2 } {
      return $arg1
   } else {
      return $arg2
   }
}

The proc command  defines a procedure - this command has three arguments:
 

  • the name of the procedure
  • a list of the arguments enclosed in curly brackets
  • the body of the procedure enclosed in curly brackets

  • In this example the procedure is called max and has two arguments, arg1 and arg2.  In the body of the procedure is a simple conditional statement to return the larger of the two arguments.

    Note:

  • use of curly brackets to enclose code fragments
  • use of $ symbol to denote 'the value of the variable'

  • And how to use the procedure..

    set x [max 3 4]
    puts "x = $x"

    This is using the set command to give a value to the variable 'x' which is the result from the command max.

    Variables

    Text strings

    Tcl treats all variables as text strings except where context requires them to be numerical.  There are several Tcl commands which operate on text strings:
     
    set set a variable parameter
    string variety of string manipulations
    append append text to a variable
    regexp regular expression matching
    regsub using regular expression to modify a string

    There are two forms of collective variables: lists and arrays.

    Lists

    CCP4i uses list structures to contain the definition of the items which will appear on a pop-up menu.
    Lists are created by the list command

    set name_list [list Pete Martyn Charles Alun]

    or (not recommended) by enclosing in curly brackets

    set name_list {Pete Martyn Charles Alun}

    Text string can be treated as a list with each word as a list item (but beware can 'lose' spaces).

    Commands which manipulate lists
     
    list Create a list
    lappend Append items to end of a list
    linsert Insert items in a list
    lreplace Replace items in a list
    concat Concatenate lists
    lindex Extract one item from a list 
    lsearch Search a list for an item
    lsort Sort a list
    llength Return the length of a list

    Arrays

    CCP4i uses arrays to group together all of the variables associated with one task - for example these might be defined by:

    set demo(NCYCLES) 5
    set demo(RESOLUTION_MAX) 3.0

    Here the array is called demo and the elements of the array are called NCYCLES and RESOLUTION_MAX
    Note that the array elements are not called 1,2,3.. (Fortran) or 0,1,2,3..  (C).

    In CCP4i there is one array associated with each task interface.
    The name of the array is decided by the core CCP4i, which ensures a unique name (usually has the same name as the task) and passes the name of the array to the procedures in the taskname.tcl file which then look like this:

    proc demo_task_window { arrayname } {

      upvar #0 $arrayname array

    --snipped--

    }

    The procedure demo_task_window is the main procedure defining the demo task.  The name of the array is passed in in the variable arrayname.  The command upvar is used to make the contents of the array visible in the context of this procedure and the variables are accessed as array(NCYCLES)  or array(RESOLUTION_MAX).

    Variables and Widgets

    The important thing that happens in the taskname.tcl file is that each variable gets associated with a widget.  As the user changes the visible widget (by typing into a text widget or picking a button or menu widget) then the value in the variable is updated.  When the user hits the run button one of the things that happens is the current value of all of the parameters are written out to a def file in the CCP4_DATABASE directory.  So taskname.tcl can be thought of as a def file editor.

    Generally the task window widgets are passive - they do not have any actions attached but it is possible to attach commands to a button and also to change the buttons at the bottom of the task window.
     

    'Indexed' Variables within CCP4i

    This is entirely a CCP4i thing!

    Variables which are used in extending frames and toggle frames (for example the variables CHAIN, RES1 and RES2 used in the definition of 'Protein Ranges to Refine' in the demo task):

    The names of the variables used in the interface to define two residue ranges (by a chain id and the first and last residue id) are:

    demo(CHAIN,1)  demo(FIRST_RES,1)  demo(LAST_RES,1)
    demo(CHAIN,2)  demo(FIRST_RES,2)  demo(LAST_RES,2)

    These are given an index number separated from the variable name by a comma.  To Tcl  the comma is just another character in the variable name. Only CCP4i understands the comma to be special character.

    In the def files, which set initial values for variables there is:

    CHAIN1,0                _chain_id               ""
    FIRST_RES,0             _res_id                 ""
    LAST_RES,0              _res_id                 ""

    The variable with the index value 0 is never accessible from the task window but is used as the initialiser for the  actual variables which are created automatically.

    There are cases of double nested extending frames, for example in heavy atom refinement the top frame defines isomorphous derivatives and the nested frame defines the heavy atoms within each derivative.  The variables to define the heavy atom coordinates might be:

    For the first derivative the coordinates of three heavy atoms:

    array(HA_X,1_1) array(HA_Y,1_1) array(HA_Z,1_1)
    array(HA_X,1_2) array(HA_Y,1_2) array(HA_Z,1_2)
    array(HA_X,1_3) array(HA_Y,1_3) array(HA_Z,1_3)

    and for the second derivative the coordinates of two heavy atoms:

    array(HA_X,2_1) array(HA_Y,2_1) array(HA_Z,2_1)
    array(HA_X,2_2) array(HA_Y,2_2) array(HA_Z,2_2)

    Note that an underscore is used as a separator (why not a comma again? doh!).