Automatic GUI Generation

Liz Potterton, July 2002

Introduction

There is no such thing as automatic GUI generation (of a non-trivial GUI that you would want to use).
GUIs need user-oriented text, sensible layout and multifarious documentation which require thoughtful human input - what the user gets is roughly proportional to what the programmer puts in  (provided there is no redundancy in defining the GUI - see point 1 below).

Requirements for GUI generation:

1) Bringing the GUI definition and the program interface definition together to avoid duplication of effort and code divergence.
2) A language-independent GUI definition.  This would mean both web-based and non-web-based GUIs could be created from the same definition and is an attempt at future-proofing against changes in technology (though it probably does not insure you against radical changes in GUI paradigms).   This is done by defining the GUI in a neutral form (XML was originally proposed) which is then interpreted by a 'GUI machine' which generates the GUI. The GUI machine could be Tcl/Tk or Java or whatever.

Pragmatically, I would also add:

3) We should exploit what we have in CCP4i
4) Ensure there is continuity with CCP4i - otherwise support will become difficult.
5) Ensure compatibility with MG so, where appropriate, a task can be run graphically or non-graphically.

Future Program Interfaces will be Simpler..?

I am not convinced about this. Consider two futuristic programs: Phasor and DMMulti (the latter is futuristic in objective if not coding), they have large, complex interfaces (even after careful rational design).  The bulk of their interface is actually input of data (heavy atom positions, rotation matrices etc.) which we might think will be separated out in future but:
a) I assume, we do want the option to expose the data in a GUI even if users do not need to input the data and will only occasionally look at it
b) A significant feature of the program interface seems to be options to select which data to actually use and to set initial weighting etc. which are attributes of elements in the complex data hierarchy.  In an ideal world these would not be necessary as the program would decide this stuff automatically, but ..
c) The programs have several operational modes - GUIs need to be customised to the operational mode.
 

Overview of the MG GUI

The MG consists of two separate processes - the 'GUI machine' is Tcl/Tk with BLT and incr Tcl (the oo extension) and with some of the basic window generation from CCP4i. - the main process is Python/C++.  The two processes communicate via sockets.  The Python top layer of the main process is responsible for defining the GUI and handling the GUI input.   The  definition of the GUI in Python is in the form of nested lists with the first word of any list being a keyword indicating the rest of the list content.  This is similar in effect to defining the GUI in XML which was the original idea but was dropped in favour of something more integrated.  The GUI definition in Python lists is (trivially) converted into Tcl nested lists and sent to the GUI process.  There is an  incr Tcl class CGUIWindow, which parses the GUI definition and generates a GUI - using the CCP4i code wherever possible.

MG requires a very different interface to CCP4i tasks - there are more 'Do It Now' buttons and more complex graphical widgets and the latter have needed a new approach.  In CCP4i each basic widget maps on to one parameter (the one exception is the file selection widget which has file name and path). The more complex widgets required by MG have multiple parameters and are coded as incr Tcl classes.

I think the MG and the program interface should use the same GUI machine but the means of generating the GUI definitions may be very different due to the very different nature of the programs.

Disclaimer/admission: The implementation so far has been rather ad hoc - I am adding to the features supported by CGUIWindow as required.
 

Components of a GUI Definition

This is to clarify some of the requirements to define a GUI.

If one parameter is represented by one GUI widget the basic GUI-definition attributes of that parameter are:

i) The permitted values (and this generally determines the type of widget used to represent the parameter)
ii) Default value
iii) Some text label
iv) Short bubble or message line style help
v) Fuller help description

and more tricky:

vi) Relation to other parameters viz. layout of GUI
vii) Relation to other parameters viz. visibility and default value
 

What To Do?

The following is half-baked, has over-generalisations and makes assumptions about non-GUI issues but here goes..

We have discussed before that the input to a program should clearly differentiate between data and program control parameters.

The Data Input
The data is usually a complex hierarchy which in the short/medium term is liable to be kept in (?XML) files and follow a data structure consistent with what comes out of the EBI-Spine initiative.    It seems reasonable to have a program-independent mechanism for creating a GUI to any of these files. There is a problem that some extra program-dependent attributes may need tagging onto the 'true' data (e.g. flagging if the data is selected or giving some initial parameter for program input).  The best GUI representation of hierarchical data is probably a tree structure like a file browser (or the MG Display Table).  The present CCP4i mechanism, 'extending frames', is not flexible enough.
We have talked about something on these lines for representing the structure of MTZ files and it also obviously applies to heavy atoms, MR solutions, domains etc..  We need a generic mega-widget (it will be, hum, non-trivial).
We expect that the basic data structure definition (for heavy atoms, MR solutions etc.) will come from the EBI-Spine initiative but the Spine definitions and this may include some of the things that we need for GUI definition but I would expect not all of the information to be appropriate (e.g. defaults and permitted values being appropriate for deposition but not program input or data definitions being very correct but not helpful).  Also the Spine definitions are liable to include additional data elements and attributes which we do not want to use.

We need to keep talking to EBI to get what we want or at least to have a clear idea of what will come out of this.

Program Control Parameters
Program control parameters are generally less complex (except those which are attributes of elements of the data structure, as discussed above).  There could/should be one file where the program interface and the basics of the GUI are defined - the items i) to v) of the GUI Definition could certainly go in such a file.

But some component of the GUI definition needs to be separate from the the program data definition because..

a) there is not necessarily a simple one-to-one correspondence between program and GUI: there may need to be alternative GUIs for different modes of the program and the program may be only one part of a bigger task for which a limited interface is provided
b) when designing a GUI you can spend a lot of time faffing with the layout - my feeling is that it is more flexible to define the layout separate from the basic components.

I would suggest that items i) to v) are part of the program definition but that there is then a separate definition of any given GUI.  The simplest form of this GUI definition would just be a list of the parameters that are to appear in the GUI and then the GUI machine will generate a window based solely on the information from the program parameter definitions.  A more complex GUI definition might override the program definition  and could encode control of visibility etc.

Overview of How It Might Work

There is no reason why a task window generated by any future mechanism can not sit side by side with existing task windows in CCP4i and no reason why the mechanisms that actually run the tasks behind the scenes can not be different.  But lets try to keep to a minimum number of alternatives (like Tcl or Python but NO other scripting languages!).

In future I would expect that the def file (or it's equivalent) is the command input to the task/program, thus removing the need for CCP4i com files.   I would suggest that the 'programs' and the equivalent of the CCP4i script files are merged and that  the top layer of the task/program is a Python script which:

1) Reads the input parameters from a def file (or equivalent)
2) Requests the data from the data manager (which is a Python 'library'/class)
3) Creates the function objects and calls the methods that do the real work
4) Communicates progress back to the main CCP4i process (or a Controller or whatever in future).

So what is 'the program' which has input parameters which have the GUI definition attributes?  It could be the C/C++ function objects or the Python script.  I think that it needs to be both.  Each function object has its own parameter definitions but then a higher level function object or a Python object can select which of these to inherit into its own parameter definition and can override attributes of any parameter.
I'm not sure how to encode this parameter definition information.  For a GUI machine to create a GUI it would need to access the parameter definition of the program/task (and then probably needs to access the parameter definitions of component function objects).  So the parameter definition probably needs to be a separate (XML?) file.  It could be a method of the task or function object but then the task/function objects will need to be instatiated before you can create a GUI - and this seems messy to me.  But there is the problem that the appropriate default parameters may be data dependent and that it would require a method of the task/function obect to determine the appropriate default value

(Aside: The MG GUI definitions are effectively methods but the MG is a very different thing, it is real time and basically one process).

Example

Consider a simple task called solve_by_fiddle which uses  Martin's Ecalc function and another C++ object function called Fiddleit (its direct methods!).  We know that Ecalc has one parameter nprm and lets say Fiddleit has parameters fiddle_init and fiddle_mode.

The parameter definition files for ecalc and fiddleit are shown below (don't complain about dodgy XML and other dodgy details).  The data tagged <TYPE> (or <TYPEDEF>),<DEFAULT>,<LABEL>,<HELP> and <HELP_TARGET> correspond to items i) to v) above and also obviously map into CCP4i.

ecalc.param_def.xml

<PARAM>nprm
    <TYPE>_positiveint1</TYPE>               #positive integer excluding 0
    <DEFAULT>10</DEFAULT>
    <LABEL>Number of bins for normalisation</LABEL>     # My guess at a user-friendly explanation of nprm
     <HELP>Some more explanation of Martyn's  parameter</HELP>
      <HELP_TARGET>ecalc::nprm</HELP_TARGET>  # A link to html or could contain some actual text
</PARAM>

fiddleit.param_def.xml

<PARAM> fiddle_init
    <TYPE> _positivereal </TYPE>
    <DEFAULT> 0.0 </DEFAULT>
    <LABEL>The starting value for fiddle <\LABEL>
    <HELP> If unknown then use default 0.0, recommended to use values up to 5.0 for low resolution</HELP>
    <HELP_TARGET> fiddleit::fiddle_init</HELP_TARGET>
</PARAM>

<PARAM>fiddle_mode
    <TYPEDEF> menu <MENU_TEXT> Fast  Medium  Slow </MENU_TEXT>
                           <MENU_KEYWORDS> FAST MEDIUM SLOW <MENU_KEYWORDS>  </TYPEDEF>
    <DEFAULT>MEDIUM</DEFAULT>
    <LABEL> Fiddleit mode</LABEL>
    <HELP> Only use fast mode for high resolution</HELP>
    <HELP_TARGET> fiddleit_mode<HELP_TARGET>
</PARAM>

solve_by_fiddle is a  Python script which will make a sensible guess at the fiddle_init parameter and so does not need to expose that parameter in it's own interface but it does have a parameter for the number of runs of fiddleit to attempt before giving up...

solve_by_fiddle.param_def.xml

<INHERIT>ecalc</INHERIT>    # Means just inherit all Ecalc parameters
<INHERIT>fiddleit::fiddle_mode</INHERIT>  # The solve_by_fiddle interface will inherit only fiddle_mode
<PARAM> ntries</PARAM>
    <TYPE>_positiveint1</TYPE>
    <DEFAULT> 3 </DEFAULT>
    <LABEL>Number of tries of fiddleit</LABEL>
    <HELP>Probably not worth more than 20 tries<HELP>
    <HELP_TARGET>solve_by_fiddle::ntries</HELP_TARGET>
</PARAM>

So solve_by_fiddle is exporting 3 parameters ecalc::nprm, fiddleit::fiddle_mode and solve_by_fiddle::ntries
A GUI definition for solve_by_fiddle will inherit the solve_by_fiddle parameter definitions and provide some definition of the GUI layout.  In the example below it will just display widgets for fiddle_mode and ntries and put the nprm parameter in a separate folder.

solve_by_fiddle.gui_def.xml

<INHERIT>solve_by_fiddle.param_def</INHERIT>
<TASK_WINDOW>
   <TITLE>Solve using Fiddle algorithm</TITLE>
   <PROTOCOL>
      <LABEL>Parameters to run the Fiddle algorithm</LABEL>
      <PARAM>fiddleit::mode</PARAM>
      <PARAM>solve_by_fiddle::ntries</PARAM>
   </PROTOCOL>
   <FOLDER><FOLDER_TITLE> Normalisation parameters </FOLDER_TITLE>
      <PARAM>elcalc::nprm</PARAM>
   </FOLDER>
</TASK_WINDOW>