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.
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.
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
We have discussed before that the input to a program should clearly differentiate between data and program control parameters.
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.
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.
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).
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>