.ds f. conductor.sec
.NH 1 "INTRODUCTION"
.XS
\s12\*(SN  INTRODUCTION\s0
.XE
.sp 2
.PP
\fBConductor\fP is a code-generating tool which must be used by
the application programmer who wishes to write an \fIxvroutine\fP. 
An xvroutine is an application which has a graphical user interface (GUI)
\fIregardless of whether or not it is executed from the command line\fP.  
For more information on the definition of an xvroutine (as opposed to 
a \fIvroutine\fP), see Chapter 1 of the Khoros Programmer's Manual.
Xvroutines will always use X windows, \fIindependently of any 
accessibility they may have through\fP \fBcantata\fP. 
These applications will  always use the X Toolkit 
and the Athena widget set indirectly 
(via the \fIxvforms\fP library); calls to Xlib, the X Toolkit and/or the
Athena Widget Set may also be used directly by the application program.
Note that the use of \fIxvforms\fP implies a system using X 
Windows, version 11, release 4, with access to the X Toolkit and 
Athena Widget Set.  Examples of \fIxvroutines\fP include all the 
major applications of Khoros; some of these include: \fBanimate, composer, 
preview, editimage, viewimage, warpimage, xprism2,\fP and \fBxprism3\fP.  
.PP
Since the proper utilization of \fBconductor\fP may seem somewhat complex to 
the novice user, it is recommended that you read this entire chapter
through at least once before attempting to use \fBconductor\fP to generate
code for you.  Also, the reader is reminded that there is much more to 
writing an xvroutine than simply using \fBconductor\fP.  One should carefully
follow the instructions given in Chapter 1 of the Khoros Programmers Manual
for writing programs under the Khoros system.  It is assumed that you
have already read Chapter 1, or were in the process of reading Chapter 1 when
you interrupted your reading to reference this document, as advised 
Chapter 1.
.sp 3
.NH 1 "USING CONDUCTOR"
.XS
\s12\*(SN  USING CONDUCTOR\s0
.XE
.sp 2
.PP
There are four major steps in using \fBconductor\fP to help you create your 
xvroutine.  First, as in the creation of vroutines, you must create your 
User Interface Specification (UIS) file that will describe the 
physical appearance of the user interface for your specific application.
Second, you must decide on the \fIlevel of extraction\fP to use.
Third, you create the link between your application and the \fIxvforms\fP
library by executing the \fBconductor\fP code generation program.
Finally, you must integrate the main driver of the graphical user interface
generated by \fBconductor\fP with the library file 
generated by \fBghostwriter\fP.
.sp 2
.NH 2 "CREATING THE UIS FILE"
.XS
      \*(SN  CREATING THE UIS FILE
.XE
.sp
.PP
To create your UIS file, one of two approaches may be taken.  
You may use the interactive UIS editor,
\fBcomposer\fP, which will automatically create the UIS file for you (for
more information, see the documentation on \fBcomposer\fP in Chapter 4
of the Khoros Programmer's Manual).
Alternatively, you may create your UIS manually with your visual editor, 
using the pre-determined form for UIS lines as described in the 
documentation on the UIS in Chapter 2 of the Khoros Programmer's Manual.  
Note that if the second method is used, careful 
attention must be paid to the syntax and position of UIS lines.   
The UIS file specifications will not be repeated here, as they
are well documented in Chapter 2 of the Khoros Programmer's Manual.
.PP
It is worth repeating here that xvroutines often have \fItwo\fP UIS files.
While in theory it is possible to use the same UIS file for both 
\fBghostwriter\fP and \fBconductor\fP, we have found that the command 
line user interface (CLUI) usually has a subset of the complete 
number of options found in the graphical user interface (GUI).  
For this reason, xvroutines usually have two UIS
files:  "xvroutine.pane" will be the shorter UIS file to be used with 
\fBghostwriter\fP to generate the CLUI, and to integrate the new program 
into \fBcantata\fP; "xvroutine.form" will be the longer UIS file to be 
used with \fBconductor\fP to generate the GUI.  
.PP
There are other differences between the "xvroutine.pane" file and the
"xvroutine.form" file.  For one thing, an "xvroutine.pane" file to be 
used with \fBghostwriter\fP need only have a single pane on a single 
subform, regardless of the complexity of UIS specified by "xvroutine.form".  
\fBGhostwriter\fP pays no attention to UIS lines that structure the 
graphical user interface, such as Master Form definitions, Guide Pane 
definitions, and Submenu definitions.  Thus, it is to your advantage to 
keep "xvroutine.pane" as simple as possible!
.PP
Another difference to note is the variable names specified on the (-F) 
lines of "xvroutine.pane" versus "xvroutine.form".  The variable name on
the (-F) line of "xvroutine.pane" will not be used by \fBghostwriter\fP,
which ignores this field.  Some people use the name of the program here.  
However,
on the (-F) line of "xvroutine.form", the one word you must NOT use
as the variable name on the (-F) line is the name of the program!  
Remember that \fBghostwriter\fP generates a data structure in which to
store command line arguments -- this data structure is always named after
the program.  Thus, if you provide the program name as the variable name
on the (-F) line of "xvroutine.form", the data structure generated by
\fBconductor\fP in which to store graphical user interface information
will also have that name.  Needless to say, the C compiler does not 
appreciate programs that have two data structures by the same name, 
and will refuse to compile your program if you make this mistake.
.PP
As you are developing your UIS file, use of the \fBpreview\fP user interface
display program is highly recommended, in order to examine how the 
graphical user interface described by your UIS will look.  
For comments and tips on using \fBpreview\fP to aid in creating the 
UIS to reflect the special needs of your application, see Chapter 3 of the
Khoros Programmer's Manual.  Make sure that no UIS errors occur.  
\fBPreview\fP will check the UIS file for you, in a limited 
fashion, and give warning or error messages when necessary.  Do not go on to 
Step 2 until you are not only satisfied with the appearance of the forms 
described by your UIS file, but also certain that you
have included every item that your program will need.  While it is a
simple procedure to modify your UIS when needed, and re-run \fBconductor\fP 
to update the code according to the new modifications, it will save time if
the original UIS that you begin with is as complete as possible.
.sp 2
.NH 2 "DECIDING ON THE LEVEL OF EXTRACTION"
.XS
      \*(SN  DECIDING ON THE LEVEL OF EXTRACTION
.XE
.sp
.PP
The \fIlevel of extraction\fP used with \fBconductor\fP refers to 
the amount of information that you want the code generated by 
\fBconductor\fP in the file "form_info.c" to extract from your
xvroutine's  graphical user interface at any one time.  
If the level of extraction is 1, the code in "form_info.c" 
will be generated so that one call from the xvroutine gets \fIall\fP 
the information from your entire user interface at once. 
If the level of extraction is 2, one call for each subform 
will get \fIonly\fP the information from that particular \fIsubform\fP.  
If the level of extraction is 3, there must be one call for each pane, 
to get \fIonly\fP the information from that \fIpane\fP. 
.PP
While deciding on the 
\fIlevel of extraction\fP is necessary \fIbefore\fP one runs \fBconductor\fP 
(since the [-l {levels of extraction} ] flag is required by \fBconductor\fP),
we will leave detailed explanation of this term for later, when the reader 
will have the background needed for a more clear understanding of the 
tradeoffs with respect to ease of programming as well as efficiency of 
providing the most suitable level of extraction.  
.sp 2
.NH 2 "RUNNING CONDUCTOR"
.XS
      \*(SN  RUNNING CONDUCTOR
.XE
.sp
.PP
The main purpose of \fBconductor\fP is to automatically generate the
code that provides the link between the \fIxvforms\fP library (which
controls the graphical user interface) and your application.  The 
\fIxvforms\fP library uses a very large and complicated data structure 
called the \fIxvf_form\fP structure to store and maintain information 
about the graphical user interface during the execution of the application.  
Since it is quite unreasonable to require that application programmer 
understand the intricacies of this data structure, the task of obtaining 
information about the user's input to the graphical user interface is 
simplified by the simple, one-level data structure that is generated by 
\fBconductor\fP in the "form_info.h" file;  this data structure is referred
to as the \fIForm Information\fP structure (its actual name depends on the
variable name provided on the (-F) line of your "xvroutine.form" file).  
In addition, \fBconductor\fP generates code in "form_init.c" to initialize 
this structure, and code in "form_info.c" to extract information from 
the form tree, and copy it into the Form Information structure where it
is available for use by the xvroutine.  
.PP
After you have created your UIS file, and are satisfied with the 
appearance and completeness of the forms it describes, you will run 
\fBconductor\fP with the name of your UIS file as input, and a 
level of extraction of 1, 2, or 3. If this is the first time 
that \fBconductor\fP has ever been run with the UIS in question, 
you will want to include the [-b 1] flag, which will indicate to 
\fBconductor\fP that you also wish to have a skeleton driver for 
the main user interface loop to be automatically generated. 
.PP
After you have run \fBconductor\fP, three files 
will be created: "form_info.h", "form_init.c", and "form_info.c". If the [-b 1] 
flag is included, an additional file, "form_drv.c" will also be created, 
in which the skeleton driver is ready to be modified for your specific use.
.sp 2
.NH 2 "INTEGRATING THE SKELETON DRIVER INTO YOUR LIBRARY FILE" 
.XS
      \*(SN  INTEGRATING THE SKELETON DRIVER INTO YOUR LIBRARY FILE
.XE
.PP
.sp
To integrate the code generated by \fBghostwriter\fP with that generated
by \fBconductor\fP, simply follow the \fB10 Easy Steps to Integration\fP:
.sp
.IP 1)
Edit the "xvroutine.h" file that was  generated by \fBghostwriter\fP.
Between the \fI/*include_includes*/\fP and \fI/*include_includes_end */\fP 
tags that appear at the top of the  file, add the lines:
.sp
#include "xvforms.h"
.br
#include "form_info.h"
.sp
If you will be using the \fIxvgraphics\fP and \fIxvdisplay\fP libraries, 
also add:
.sp
#include "xvgraphics.h"
.br
#include "xvdisplay.h"
.sp
While you are in the "xvroutine.h" file, add the following definition 
between the \fI/*include_additions*/\fP and \fI/*include_additions_end */\fP 
tags that appear in that file:
.sp
Display *display;
.sp
.IP 2)
Edit the "lxvroutine.c" file that was generated by \fBghostwriter\fP. 
Between the \fI/*library_includes*/\fP and \fI/*library_includes_end */\fP tags
that appear at the top of the file, add the line:
.br
#include "xvroutine.h" 
.sp
.IP 3)
Copy the declaration of the main driver from "form_drv.c", (the main driver
is always the first code generated; it will be named 'run_xxx' where xxx is
the variable name at the end of your UIS file's [-F] line) and insert it
into "lxvroutine.c"  between the /* library_def */\fP and
\fI/* library_def_end */\fP tags that appear in that file.  Delete the
library definition (\fIlxvroutine()\fP) that was generated 
by \fBghostwriter\fP. 
.IP 4)
Copy the entire body of the main driver from "form_drv.c", and
insert it into "lxvroutine.c"  between the /* library_code */\fP and
\fI/* library_code_end */\fP tags that appear in that file. Be sure that
the body of the main driver appears \fIabove\fP the \fIreturn(TRUE)\fP
statement that should remain as part of your library routine.  
.PP
While you're at it, correctly modify the lines at about line 90 that read:
.sp
form_filestring = xvf_strcpy("your_filename.form");
.br
form_pathname   = xvf_strcpy("your_filename_directory");
.sp
The \fIform_filestring\fP should be assigned the name of your UIS file, while
the \fIform_pathname\fP is usually set to "./" while the xvroutine is under
development, and changed to 
\f(CWKHOROS_CONTRIB/repos/xvroutine/xvroutine.pane\fP when it is installed.
.IP 5)
Now edit the "form_drv.c" file.  Delete the long comment that begins,
"Advice for the user of this code'.  Delete the header, the definition, 
and the body of the main driver (the one you just copied into "lxvroutine.c").
Replace the latter three #includes at the top of the "form_drv.c" file
with the single statement:
.br
#include "xvroutine.h"
.sp
Leave the rest of the code generated in "form_drv.c" alone.
.sp
.IP 6)
Edit the "xvroutine.c" file: between the /* main_library_call */\fP and
\fI/* main_library_call_end */\fP tags that appear in that file, add your
call to the main driver that now exists in the "lxvroutine.c" file. It should
look like this:
.sp
run_xvroutine(argc, argv, program);
.sp
.IP 7)
At this point, check to make sure that you have the following:
.sp
\(bu
The main user interface driver generated by \fBconductor\fP, now correctly
inserted into the "lxvroutine.c" file, followed by a \fI return(TRUE);\fP
statement.
.sp
\(bu
The "form_drv.c" file, now missing its main driver, the header for the
driver, and its long comment. Its original include statements are 
replaced by a single reference to "xvroutine.h".   It should still have 
at least two remaining routines that were automatically generated by
\fBconductor\fP.  These are the routines that you will modify most often
when adding functionality to your xvroutine.
.sp
\(bu
The "xvroutine.c" file, now with a correct call to your "library" routine.
.sp
.IP 8)
Give the "form_drv.c" file a new name. We suggest "run_xvroutine.c".
.IP 9)
Finally, execute: 
.sp
\f(CW
% imkmf 
.br
% makemake
\fP
.sp
This will update your Makefile, and include the new "run_xvroutine.c" file.  
Now Execute:
.sp
\f(CW
% make 
\fP
.sp
to compile your new (non-functional) program, to make sure that you 
followed these instructions correctly.  If all is well, your GUI should
come up, but will not respond (as you have not yet added any functionality).
.sp
.IP 10)
LAST, BUT NOT LEAST, don't forget to run:
.sp
\f(CW
% ghostreader -name xvroutine
\fP
.sp
This is very important, so that when you decide to run \fBghostwriter\fP 
again, the updated PS file will insure that you didn't just spend a 
lot of carefully wasted time!
.sp 3
.sp 3
.NH 1 "ILLUSTRATION BY EXAMPLE"
.XS
\s12\*(SN  ILLUSTRATION BY EXAMPLE\s0
.XE
.sp 2
.PP
For illustration purposes, we will go through the entire process with a sample 
UIS,  which illustrates at least one example of most types
of lines that may occur in the user interface specification file.  
This sample UIS utilizes a master form (note that the use 
of a master form is optional).  This master form has a workspace, as well
as 2 subform buttons, 
which will bring up two different subforms. The first subform has a 
guide pane (note that the use of a guide pane is also optional) 
with 2 guide buttons, each of which will bring up a different pane. 
The second subform has only a single pane. The panes on the first subform 
illustrates the use of Input Files and Output Files, while the second subform 
illustrates the use of toggles, integers, floats, strings, and mutually 
exclusive groups.  Both subforms use logicals and action buttons.
.bp
.NH 2 "AN EXAMPLE UIS FILE"
.XS
      \*(SN  AN EXAMPLE UIS FILE
.XE
.sp 2
.ps 8
\f(CW
# This User Interface Description File illustrates the use of forms with a
.br
# Master having 2 subform buttons.  Each subform button brings up a
.br
# different subform.  The first subform has a guide pane with 2 guide buttons;
.br
# each guide button will bring up a different pane.  The second subform
.br
# has only a single pane.
.sp
-F 4.2 1 1 66x100+10+20 +35+1 'Example Master Form' Master
.br
 -S 1 1
.br
   -d 1 0 12x2+2+4 'Subform1'
.br
   -d 1 0 12x2+2+6 'Subform2'
.br
   -n 1 0 12x2+2+10 'Master Action' 'description of action' master_action
.br
   -w 512x256+15+2 +25+1 'Workspace' 'workspace widget' workspace
.br
   -H 1   12x2+2+14 'Help' 'help for master' /dev/null
.br
   -H 1   10x1+77+0 'Copyright' 'Copyright' $KHOROS_HOME/doc/xprism/xprism2/copyright
.br
   -Q 1 0 12x2+2+16 'QUIT'
.br
 -E
.br
 -M 1 0 66x100+10+20 +30+0 'Sample SubForm 1' Subform1
.br
   -G 1 20x20+0+1 +5+1 'Guide Pane'
.br
     -g 1 1 15x2+2+3 'Input'
.br
     -g 1 0 15x2+2+5 'Output'
.br
     -m 1 0 15x2+2+8 'Subform Action' 'description of action' operation
.br
     -Q 0 0 14x2+2+11 'QUIT'
.br
   -E
.br
   -P 1 1 40x20+19+1 +5+0 'Example of Input File & Logicals' input
.br
     -I 1 0 0 1 0 1 43x1+0+2 +0+0 ' ' 'Input File' 'file to be used' infile
.br
     -l 1 0 0 1 0 40x1+4+5 +0+0 1 'Add File' 'false' 'true' 'adds a new file' add_file
.br
     -l 1 0 0 1 0 40x1+4+7 +0+0 0 'Delete File' 'false' 'true' 'deletes an old file' delete_file
.br
     -a 1 0 20x2+2+9 'Get Input' 'retrieves input' get_input
.br
   -E
.br
   -P 1 0 40x20+19+1 +12+0 'Example of Output File' output
.br
     -O 1 0 0 1 1 0 40x1+0+2 +0+0 ' ' 'Output File' 'file to be saved' outfile
.br
     -a 1 0 20x2+2+9 'Save File' 'stores output' save_output
.br
   -E
.br
 -E
.br
 -M 1 0 66x100+10+20 +10+0 'Sample SubForm 2' Subform2
.br
   -P 1 1 40x20+1+1 +5+0 'Example of Toggle & Floats' transforms
.br
     -T 1 0 0 1 0 40x1+2+2 +0+0 3 'Toggle example:' 'example' trans_type
.br
       -l 1 0 1 0 0 40x1+1+1 +0+0 0 'choice 1' 'false' 'true' 'selects choice 1' ch1
.br
       -l 1 0 1 0 0 40x1+14+1 +0+0 0 'choice 2' 'false' 'true' 'selects choice 2 ' ch2
.br
       -l 1 0 1 1 0 40x1+27+1 +0+0 0 'choice 3' 'false' 'true' 'selects choice 3 ' ch3
.br
     -E
.br
     -f 1 0 0 1 0 40x1+0+5 +0+0 -100 100 0 'x value' 'the value of X ' x_val
.br
     -f 1 0 0 1 0 8x1+0+7 +0+0 -100000 100000 0 'y value' 'the value of Y ' y_val
.br
     -i 1 0 0 1 0 34x1+5+9 +0+0 -100 100 0 'integer 2' 'selects int 2 ' int2
.br
     -i 1 0 0 1 0 19x1+5+10 +0+0 -1 -1 -6 'integer 1' 'selects int 1 ' int1
.br
     -C 1
.br
       -s 1 0 1 1 0 34x1+5+12 +0+0 ' ' 'string 1' 'first string' string1
.br
       -s 1 0 1 0 0 34x1+5+13 +0+0 ' ' 'string 2' 'second string' string2
.br
       -s 1 0 1 0 0 34x1+5+14 +0+0 ' ' 'string 3' 'third string' string3
.br
       -i 1 0 1 0 0 34x1+5+15 +0+0 -1 -1 -6 'integer ' 'integer instead of a string' int4
.br
     -E
.br
     -a 1 0 15x2+2+17 'Do Something' ' ' do_something
.br
     -Q 0 0 7x2+32+17 'QUIT'
.br
   -E
.br
 -E
.br
-E
.br
\fP
.sp 2
.NH 2 "RUNNING CONDUCTOR TO GENERATE CODE"
.XS
      \*(SN  RUNNING CONDUCTOR TO GENERATE CODE
.XE
.sp 2
.PP
Now we will use \fBconductor\fP with the UIS file listed above
to generate the code that will link our application program with 
the user interface.  We create a new directory, and go into it.
For this simple case, we will use a level of extraction 
of 1 (the impact of which will be explained later). We will specify the [-b] 
flag, to indicate that we would like a skeleton driver to be generated for 
us. We execute:
.sp  
\f(CW
% conductor -i example.form -l 1 -b 1
\fP
.sp
\fBconductor\fP responds with the following messages , indicating 
that all went well, and that the necessary code has been 
generated successfully:
.sp
\f(CW
Ready to generate form_info.h, 
.br
form_init.c, form_info.c, and form_drv.c 
.sp 2 
cnd_gen_form_struct:
.br
Done with generating forminfo structure:
.br
form information structure in 'form_info.h'
.sp 
cnd_gen_init_forminfo:
.br
Done with generating initialization code:
.br
routine '_xvf_init_Master' now in 'form_init.c'
.sp 
cnd_gen_get_forminfo:
.br
Done with generating extraction code:
.br
routine '_xvf_get_Master' now in 'form_info.c'
.sp
cnd_gen_drivers:
.br
Done with generating driver code, now in 'form_drv.c'
\fP
.sp 2
We now have had four files generated for us:
.sp
\fI"form_info.h":\fP defines the C structure into which information 
from the forms will be extracted, and in which the xvroutine will look 
for current values, such as the value of a string selection, the current 
value of a toggle, the latest value of an integer, or which subform is 
currently selected.
.sp
\fI"form_init.c":\fP contains the C code which will initialize the 
abovementioned structure according to the default values that were 
specified in our example UIS file.
.sp
\fI"form_info.c":\fP contains the C code which will extract 
information from the graphical user interface, so that the xvroutine
may use it.
.sp
\fI"form_drv.c":\fP  contains the C skeleton driver that we will integrate
with the driver generated by \fBghostwriter\fP using the procedure outline
earlier, and modify to fit the needs of our particular xvroutine.
.sp
.PP
To better understand each of these files, and how they fit into the scheme of
the application programmer who wishes to use the \fIxvforms\fP 
graphical user interface, let us examine each one in turn.  
All four generated files, along with the UIS file, "example.form" 
used in this example, can be found in 
\f(CWKHOROS_HOME/manual/conductor/example.\fP 
.sp 2
.NH 3 "Form Information Structure - form_info.h"
.XS
              \*(SN  Form Information Structure
.XE
.sp
.PP
The form information structure will be automatically generated
in "form_info.h". It is created according to the variable names 
which must be specified on any UIS line that describes a 
selection, pane, subform, or form.  Therefore, proper
care should be taken by the application programmer to be sure that these
variable names appear in the UIS on every line on which they are required, 
and that they are named appropriately and meaningfully. Warning: the 
\fBpreview\fP program will not be able to generate an error message if any 
of these variable names is missing or incorrect!  The following table 
details, for each line in the UIS that requires a variable name, 
what becomes of that variable name, and what part it plays in the 
creation of the Form Information structure. For instance, note that 
the variable name on the first line of our example UIS (the -F line)
will cause the Form Information structure in our example to be typedef'ed 
by the name of "Master".  Again, remember that you should \fInot\fP use the
name of your program as the variable name on the (-F) line, as you do not
want the name of the Form Information structure to collide with the name of
the structure for command line arguments generated by \fBghostwriter\fP.
.sp
.TS
.if \n+(b.=1 .nr d. \n(.c-\n(c.-1
.de 35
.ps \n(.s
.vs \n(.vu
.in \n(.iu
.if \n(.u .fi
.if \n(.j .ad
.if \n(.j=0 .na
..
.nf
.nr #~ 0
.if \n(.T .if n .nr #~ 0.6n
.ds #d .d
.if \n(.z .ds #d nl
.fc
.nr 33 \n(.s
.nr 39 \n(.s
.rm 46 47
.nr 34 \n(.lu
.eo
.am 47
.br
.di a+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
the Form Information structure itself 
.ad
.br
.di
.nr a| \n(dn
.nr a- \n(dl
..
.ec \
.eo
.am 47
.br
.di b+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
an integer flag inside the Form Information 
structure.  If set to 1 (TRUE), indicates that 
the corresponding subform has been selected, 
and that information inside the corresponding
Subform Information structure should be used.
.ad
.br
.di
.nr b| \n(dn
.nr b- \n(dl
..
.ec \
.eo
.am 47
.br
.di c+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
an integer flag inside the Form Information
structure. If set to 1 (TRUE), indicates that
the user wants to take the specified action,
and that the application program should act
accordingly.
.ad
.br
.di
.nr c| \n(dn
.nr c- \n(dl
..
.ec \
.eo
.am 47
.br
.di d+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
a pointer inside the Form Information structure 
that accesses the SubForm Information structure 
in which will reside the information about that
subform. Note: the name of the Subform Information 
structure itself is taken from the variable
on the (-F) StartForm line, appended to the
variable on the (-M) StartSubform line, with
an "_" separating the words.
.ad
.br
.di
.nr d| \n(dn
.nr d- \n(dl
..
.ec \
.eo
.am 47
.br
.di e+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
an integer flag inside the Subform Information 
structure.  If set to 1 (TRUE), indicates that 
the corresponding Pane has been selected, 
and that information inside the corresponding
Pane Information structure should be used.
.ad
.br
.di
.nr e| \n(dn
.nr e- \n(dl
..
.ec \
.eo
.am 47
.br
.di f+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
an integer flag inside the Subform Information
structure. If set to 1 (TRUE) indicates that
the user wants to take the specified action,
and that the application program should act
accordingly.
.ad
.br
.di
.nr f| \n(dn
.nr f- \n(dl
..
.ec \
.eo
.am 47
.br
.di g+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
a pointer inside the SubForm Information 
structure that accesses the Pane Information 
structure in which will reside the information 
about that pane.  Note: the name of the Pane Information 
structure itself is taken from the variable
on the (-M) StartSubForm line, appended to the
variable on the (-P) StartPane line, with
an "_" separating the words.
.ad
.br
.di
.nr g| \n(dn
.nr g- \n(dl
..
.ec \
.eo
.am 47
.br
.di h+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
an integer flag inside the Pane Information
structure. If set to 1 (TRUE) indicates that
the user wants to take the specified action,
and that the application program should act
accordingly.
.ad
.br
.di
.nr h| \n(dn
.nr h- \n(dl
..
.ec \
.eo
.am 47
.br
.di i+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
string inside the Pane Information struct
.ad
.br
.di
.nr i| \n(dn
.nr i- \n(dl
..
.ec \
.eo
.am 47
.br
.di j+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
string inside the Pane Information struct
.ad
.br
.di
.nr j| \n(dn
.nr j- \n(dl
..
.ec \
.eo
.am 47
.br
.di k+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
string inside the Pane Information struct
.ad
.br
.di
.nr k| \n(dn
.nr k- \n(dl
..
.ec \
.eo
.am 47
.br
.di l+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
integer inside the Pane Information struct
.ad
.br
.di
.nr l| \n(dn
.nr l- \n(dl
..
.ec \
.eo
.am 47
.br
.di m+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
float inside the Pane Information struct
.ad
.br
.di
.nr m| \n(dn
.nr m- \n(dl
..
.ec \
.eo
.am 47
.br
.di n+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
boolean inside the Pane Information struct
.ad
.br
.di
.nr n| \n(dn
.nr n- \n(dl
..
.ec \
.35
.nf
.ll \n(34u
.if \n(.z \{\
.	ch #f
.	wh \n(nlu+\n(.tu-2v #f\}
.eo
.de #f
.ie \n(#& \{ \
.	nr #& 0
.	nr #| 1
.	di #o \}
.el \{ \
.	ch #f
.	nr T. 1
.	if \n(#| .sp
.	T#
.	sp \n(.tu
.	mk #T
.	nr #a \n(#T
.	nr #c \n(#T
.	nr ^a \n(#T
.	nr ^b \n(#T
.	if \n(#| \{ \
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.		in 0
.		#+
.		in
.		rm #+
.		mk 32
.		nr #| 0\}
.	wh \n(nlu+\n(.tu-2v #f \}
..
.de #%
.if \n(.z#o \{ \
.	sp |0u
.	in 0
.	#+
.	in
.	sp |\n(.hu
.	di
.	rn #o #+ \}
..
.ec
.nr 46 0
.nr 38 \wvariable name on UIS line
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-F) StartForm
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-d) SubformButton
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-n) MasterAction
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-M) StartSubForm
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-g) GuideButton
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-m) SubformAction
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-P) StartPane
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-a) PaneAction
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-I) InputFile
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-I) OutputFile
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-s) StringSel
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-i) IntegerSel
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-f) FloatSel
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-l) LogicSel
.if \n(46<\n(38 .nr 46 \n(38
.46
.rm 46
.nr 47 0
.nr 38 \wbecomes the name of this element in the structure
.if \n(47<\n(38 .nr 47 \n(38
.47
.rm 47
.nr 38 \n(a-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(b-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(c-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(d-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(e-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(f-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(g-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(h-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(i-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(j-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(k-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(l-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(m-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(n-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \wKey to Variables-\n(46-3n-\n(47
.if \n(38>0 .nr 38 \n(38/1
.if \n(38<0 .nr 38 0
.nr 46 +\n(38
.35
.nf
.ll \n(34u
.nr 38 1n
.nr 45 0
.nr 40 \n(45+((2*\n(38)/2)
.nr 46 +\n(40
.nr 41 \n(46+((6*\n(38)/2)
.nr 47 +\n(41
.nr TW \n(47
.nr TW +((2*\n(38)/2)
.ne 16v+(0u*(\n(.vu-\n(.sp))+(2u*(\n(.vu-\n(.sp))
.fc  
.nr #T 0-1
.nr #a 0-1
.nr #c 0-1
.nr #a 0-1
.eo
.de T#
.nr 38 \n(.s
.ps \n(39p
.nr 35 1m
.ds #d .d
.if \n(.z .ds #d nl
.mk ##
.nr ## -1v
.ls 1
.if \n(T. .vs \n(.vu-\n(.sp
.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.if \n(T. .vs
.if \n(#T>=0 .nr #a \n(#T
.if \n(#c<0  .nr #c \n(#T
.if \n(#a>=0 \{\
.	sp -1
.	ie \n(#a=\n(#T \{\
\h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'\}
.	el \{\
\h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'\}\}
.if \n(#c>=0 \{\
.	sp -1
.	ie \n(#c=\n(#T \{\
.		ie \n(3a \{\
\h'(|\n(41u+|\n(46u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'\}
.		el \{\
\h'(|\n(41u+|\n(46u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#cu-\n(35u'\s0\v'\n(\*(#du-\n(#cu+\n(35u'\h'|\n(TWu'\}\}
.	el \{\
.	nr 3a 1
\h'(|\n(41u+|\n(46u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#cu-\n(35u'\s0\v'\n(\*(#du-\n(#cu+\n(35u'\h'|\n(TWu'\}\}
.if \n(#a>=0 \{.sp -1
.	ie \n(#a=\n(#T \{\
\h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\}
.	el \{\
\h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\}\}
.nr #c 0-1
.ls
.ps \n(38p
..
.ec
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.mk #a
.nr 32 0
.nr 32 \n(32u+\n(.du+2p
.ta \n(47u 
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'Key to Variables
.if \n(.tu<=2v .#f
.nr tH 0
.mk #c
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'variable name on UIS line\h'|\n(41u'becomes the name of this element in the structure
.nr tH 0
.sp
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(a|u>\n(32u .nr 32 \n(a|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(a-u)/2u
.in +\n(37u
.ie \n(a|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(a|>\n(tH .nr tH \n(a|
.a+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-F) StartForm\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(b|u>\n(32u .nr 32 \n(b|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(b-u)/2u
.in +\n(37u
.ie \n(b|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(b|>\n(tH .nr tH \n(b|
.b+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-d) SubformButton\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(c|u>\n(32u .nr 32 \n(c|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(c-u)/2u
.in +\n(37u
.ie \n(c|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(c|>\n(tH .nr tH \n(c|
.c+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-n) MasterAction\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(d|u>\n(32u .nr 32 \n(d|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(d-u)/2u
.in +\n(37u
.ie \n(d|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(d|>\n(tH .nr tH \n(d|
.d+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-M) StartSubForm\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(e|u>\n(32u .nr 32 \n(e|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(e-u)/2u
.in +\n(37u
.ie \n(e|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(e|>\n(tH .nr tH \n(e|
.e+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-g) GuideButton\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(f|u>\n(32u .nr 32 \n(f|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(f-u)/2u
.in +\n(37u
.ie \n(f|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(f|>\n(tH .nr tH \n(f|
.f+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-m) SubformAction\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(g|u>\n(32u .nr 32 \n(g|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(g-u)/2u
.in +\n(37u
.ie \n(g|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(g|>\n(tH .nr tH \n(g|
.g+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-P) StartPane\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(h|u>\n(32u .nr 32 \n(h|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(h-u)/2u
.in +\n(37u
.ie \n(h|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(h|>\n(tH .nr tH \n(h|
.h+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-a) PaneAction\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(i|u>\n(32u .nr 32 \n(i|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(i-u)/2u
.in +\n(37u
.ie \n(i|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(i|>\n(tH .nr tH \n(i|
.i+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-I) InputFile\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(j|u>\n(32u .nr 32 \n(j|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(j-u)/2u
.in +\n(37u
.ie \n(j|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(j|>\n(tH .nr tH \n(j|
.j+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-I) OutputFile\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(k|u>\n(32u .nr 32 \n(k|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(k-u)/2u
.in +\n(37u
.ie \n(k|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(k|>\n(tH .nr tH \n(k|
.k+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-s) StringSel\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(l|u>\n(32u .nr 32 \n(l|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(l-u)/2u
.in +\n(37u
.ie \n(l|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(l|>\n(tH .nr tH \n(l|
.l+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-i) IntegerSel\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(m|u>\n(32u .nr 32 \n(m|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(m-u)/2u
.in +\n(37u
.ie \n(m|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(m|>\n(tH .nr tH \n(m|
.m+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-f) FloatSel\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(n|u>\n(32u .nr 32 \n(n|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(n-u)/2u
.in +\n(37u
.ie \n(n|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(n|>\n(tH .nr tH \n(n|
.n+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-l) LogicSel\h'|\n(41u'
.sp |\n(32u
.fc
.ch #f
.rm #f
.nr T. 1
.T# \n(T.
.rm T#
.rr 3a
.35
.nr #a 0
.nr #c 0
.rm a+
.rm b+
.rm c+
.rm d+
.rm e+
.rm f+
.rm g+
.rm h+
.rm i+
.rm j+
.rm k+
.rm l+
.rm m+
.rm n+
.TE
.if \n-(b.=0 .nr c. \n(.c-\n(d.-111
.sp 2
.PP
Not all the lines in the UIS have a variable;  some lines don't need one.
In some cases, the applicable information has already been specified, while
in others, the name for the generated elements is assumed.  
.sp 2
.TS
.if \n+(b.=1 .nr d. \n(.c-\n(c.-1
.de 35
.ps \n(.s
.vs \n(.vu
.in \n(.iu
.if \n(.u .fi
.if \n(.j .ad
.if \n(.j=0 .na
..
.nf
.nr #~ 0
.if \n(.T .if n .nr #~ 0.6n
.ds #d .d
.if \n(.z .ds #d nl
.fc
.nr 33 \n(.s
.nr 39 \n(.s
.rm 46 47
.nr 34 \n(.lu
.eo
.am 47
.br
.di a+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
the Form Information structure is already used 
for the parameters on the master.
.ad
.br
.di
.nr a| \n(dn
.nr a- \n(dl
..
.ec \
.eo
.am 47
.br
.di b+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
the name for the Subform Information structure
is already provided on the (-M) StartSubForm
line - no need to replicate info.
.ad
.br
.di
.nr b| \n(dn
.nr b- \n(dl
..
.ec \
.eo
.am 47
.br
.di c+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
the application programmer has no need to know
when the user selects "Help", since xvforms 
displays online help automatically
.ad
.br
.di
.nr c| \n(dn
.nr c- \n(dl
..
.ec \
.eo
.am 47
.br
.di d+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
the int flag in the Form Information, Subform 
Information, or Pane Information structure will always
be named "quit".  No need for any other name.
.br
.di
.nr d| \n(dn
.nr d- \n(dl
..
.ec \
.eo
.am 47
.br
.di e+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
the name for the Pane Information structure
is already provided on the (-M) StartSubForm
line - no need to replicate info.
.ad
.br
.di
.nr e| \n(dn
.nr e- \n(dl
..
.ec \
.eo
.am 47
.br
.di f+
.35
.ft \n(.f
.ll \n(34u*1u/3u
.if \n(.l<\n(47 .ll \n(47u
.in 0
.na
a blank label on the form accepts no input
.ad
.br
.di
.nr f| \n(dn
.nr f- \n(dl
..
.ec \
.35
.nf
.ll \n(34u
.if \n(.z \{\
.	ch #f
.	wh \n(nlu+\n(.tu-2v #f\}
.eo
.de #f
.ie \n(#& \{ \
.	nr #& 0
.	nr #| 1
.	di #o \}
.el \{ \
.	ch #f
.	nr T. 1
.	if \n(#| .sp
.	T#
.	sp \n(.tu
.	mk #T
.	nr #a \n(#T
.	nr #c \n(#T
.	nr ^a \n(#T
.	nr ^b \n(#T
.	if \n(#| \{ \
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.		in 0
.		#+
.		in
.		rm #+
.		mk 32
.		nr #| 0\}
.	wh \n(nlu+\n(.tu-2v #f \}
..
.de #%
.if \n(.z#o \{ \
.	sp |0u
.	in 0
.	#+
.	in
.	sp |\n(.hu
.	di
.	rn #o #+ \}
..
.ec
.nr 46 0
.nr 38 \wUIS line
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-S) StartMaster:
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-d) SubFormButton:
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-H) HelpSel:
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-Q) Quit:
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-g) GuideButton:
.if \n(46<\n(38 .nr 46 \n(38
.nr 38 \w(-b) Blank:
.if \n(46<\n(38 .nr 46 \n(38
.46
.rm 46
.nr 47 0
.nr 38 \wThe reason why no variable is needed for this line
.if \n(47<\n(38 .nr 47 \n(38
.47
.rm 47
.nr 38 \n(a-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(b-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(c-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(d-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(e-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \n(f-
.if \n(47<\n(38 .nr 47 \n(38
.nr 38 \wThe following UIS lines need no variable:-\n(46-3n-\n(47
.if \n(38>0 .nr 38 \n(38/1
.if \n(38<0 .nr 38 0
.nr 46 +\n(38
.35
.nf
.ll \n(34u
.nr 38 1n
.nr 45 0
.nr 40 \n(45+((2*\n(38)/2)
.nr 46 +\n(40
.nr 41 \n(46+((6*\n(38)/2)
.nr 47 +\n(41
.nr TW \n(47
.nr TW +((2*\n(38)/2)
.ne 8v+(0u*(\n(.vu-\n(.sp))+(2u*(\n(.vu-\n(.sp))
.fc  
.nr #T 0-1
.nr #a 0-1
.nr #c 0-1
.nr #a 0-1
.eo
.de T#
.nr 38 \n(.s
.ps \n(39p
.nr 35 1m
.ds #d .d
.if \n(.z .ds #d nl
.mk ##
.nr ## -1v
.ls 1
.if \n(T. .vs \n(.vu-\n(.sp
.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.if \n(T. .vs
.if \n(#T>=0 .nr #a \n(#T
.if \n(#c<0  .nr #c \n(#T
.if \n(#a>=0 \{\
.	sp -1
.	ie \n(#a=\n(#T \{\
\h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'\}
.	el \{\
\h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'\}\}
.if \n(#c>=0 \{\
.	sp -1
.	ie \n(#c=\n(#T \{\
.		ie \n(3a \{\
\h'(|\n(41u+|\n(46u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'\}
.		el \{\
\h'(|\n(41u+|\n(46u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#cu-\n(35u'\s0\v'\n(\*(#du-\n(#cu+\n(35u'\h'|\n(TWu'\}\}
.	el \{\
.	nr 3a 1
\h'(|\n(41u+|\n(46u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#cu-\n(35u'\s0\v'\n(\*(#du-\n(#cu+\n(35u'\h'|\n(TWu'\}\}
.if \n(#a>=0 \{.sp -1
.	ie \n(#a=\n(#T \{\
\h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\}
.	el \{\
\h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\}\}
.nr #c 0-1
.ls
.ps \n(38p
..
.ec
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.mk #a
.nr 32 0
.nr 32 \n(32u+\n(.du+2p
.ta \n(47u 
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'The following UIS lines need no variable:
.if \n(.tu<=2v .#f
.nr tH 0
.mk #c
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'UIS line\h'|\n(41u'The reason why no variable is needed for this line
.nr tH 0
.sp
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(a|u>\n(32u .nr 32 \n(a|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(a-u)/2u
.in +\n(37u
.ie \n(a|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(a|>\n(tH .nr tH \n(a|
.a+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-S) StartMaster:\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(b|u>\n(32u .nr 32 \n(b|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(b-u)/2u
.in +\n(37u
.ie \n(b|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(b|>\n(tH .nr tH \n(b|
.b+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-d) SubFormButton:\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(c|u>\n(32u .nr 32 \n(c|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(c-u)/2u
.in +\n(37u
.ie \n(c|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(c|>\n(tH .nr tH \n(c|
.c+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-H) HelpSel:\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(d|u>\n(32u .nr 32 \n(d|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(d-u)/2u
.in +\n(37u
.ie \n(d|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(d|>\n(tH .nr tH \n(d|
.d+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-Q) Quit:\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(e|u>\n(32u .nr 32 \n(e|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(e-u)/2u
.in +\n(37u
.ie \n(e|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(e|>\n(tH .nr tH \n(e|
.e+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-g) GuideButton:\h'|\n(41u'
.sp |\n(32u
.if \n(.tu<=2v .#f
.nr tH 0
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.nr 32 0
.if \n(f|u>\n(32u .nr 32 \n(f|u
.nr 32 \n(32u+\n(.du+2p
.ta \n(46u \n(47u 
.mk ##
.nr 37 (\n(41u+\n(47u-\n(f-u)/2u
.in +\n(37u
.ie \n(f|>\n(.t .nr #& 1
.el .nr #& 0
.if \n(f|>\n(tH .nr tH \n(f|
.f+
.#%
.in -\n(37u
.mk 38
.if \n(38>\n(32 .nr 32 \n(38
.sp |\n(##u
.nr 35 1m
.nr 31 \n(.f
.af 31 01
\&\h'|\n(40u'(-b) Blank:\h'|\n(41u'
.sp |\n(32u
.fc
.ch #f
.rm #f
.nr T. 1
.T# \n(T.
.rm T#
.rr 3a
.35
.nr #a 0
.nr #c 0
.rm a+
.rm b+
.rm c+
.rm d+
.rm e+
.rm f+
.TE
.if \n-(b.=0 .nr c. \n(.c-\n(d.-45
.sp 2
.PP
By looking at the table above, and comparing it with the lines in our example
UIS file, the user may be able to get a fairly good idea of what the 
Form Information structure generated by \fBconductor\fP in our 
"form_info.h" file should look like.  For those who don't feel like thinking
about it, the structure follows:
.sp 
.B
C Structure generated by conductor
.R
.sp 
\f(CW
typedef struct {
.sp
        char *infile;
.br
        int infile_index;
.sp
        int add_file;
.br
        int add_file_index;
.sp
        int delete_file;
.br
        int delete_file_index;
.sp
        int get_input;
.br
        int get_input_index;
.sp
} SubForm1_input;
.sp
typedef struct {
.sp
        char *outfile;
.br
        int outfile_index;
.br
        int outfile_selected;
.sp
        int save_output;
.br
        int save_output_index;
.sp
} SubForm1_output;
.sp
typedef struct {
.sp
        int operation;
.sp
        SubForm1_input  *input;
.br
        int input_selected;
.br
        int input_index;
.br
        int input_gb_index;
.sp
        SubForm1_output  *output;
.br
        int output_selected;
.br
        int output_index;
.br
        int output_gb_index;
.sp
        int quit;
.sp
}  Master_SubForm1;
.sp
typedef struct {
.sp
        int trans_type_val;
.br
        int trans_type_index;
.sp
        float x_val;
.br
        int x_val_index;
.sp
        float y_val;
.br
        int y_val_index;
.sp
        int int2;
.br
        int int2_index;
.sp
        int int1;
.br
        int int1_index;
.sp
        char *string1;
.br
        int string1_index;
.br
        int string1_selected;
.sp
        char *string2;
.br
        int string2_index;
.br
        int string2_selected;
.sp
        char *string3;
.br
        int string3_index;
.br
        int string3_selected;
.sp
        int int4;
.br
        int int4_index;
.br
        int int4_selected;
.sp
        int do_something;
.br
        int do_something_index;
.sp
        int quit;
.sp
} SubForm2_transforms;
.sp
typedef struct {
.sp
        SubForm2_transforms  *transforms;
.br
        int transforms_selected;
.br
        int transforms_index;
.br
        int transforms_gb_index;
.sp
}  Master_SubForm2;
.sp
typedef struct { 
.sp
        int master_action;
.sp
        int workspace_index;
.br
        Widget workspace;
.sp
        Master_SubForm1  *SubForm1;
.br
        int SubForm1_selected;
.br
        int SubForm1_index;
.br
        int SubForm1_sfb_index;
.sp
        Master_SubForm2  *SubForm2;
.br
        int SubForm2_selected;
.br
        int SubForm2_index;
.br
        int SubForm2_sfb_index;
.sp
        int quit;
.sp
 }  Master; 
\fP
.sp 2
.PP
By referring to the example UIS file, see how
variables on (-P) StartPane lines will dictate the names of low-level Pane 
Information structures; variable names on selections within each pane will
appear as elements in the Pane Information structures.  Variable names on (-M) 
StartSubForm lines will become the names of the higher-level Subform Information
structures, each of which will have a pointer to the Pane Information 
structure for each pane in its subform.  Finally, the name of the (-F) 
StartForm line will become the name of the entire Form Information structure, 
and will contain a pointer to each of the Subform Information structures. 
Thus, the variable names appearing at the ends of most lines of the user 
interface description dictate the entire 3-level Form Information structure.
.PP
Note that each selection within a pane, as well as guide buttons,
subform buttons, panes, and subforms, all have an "_index"
variable generated for them; this field is for use with calls
to \fIxvf_change_input()\fP (for more info on the \fIxvf_change_input()\fP
routine, see the man page on \fIxvforms\fP).
In addition, boolean "_selected" fields are generated for panes and subforms;
in this way, the application programmer may stay informed as to which pane on
which subform is being employed by the user at any given time, or, in other
words, exactly where the input from the user interface is coming from.
.sp 2
.NH 3 "Form Information Structure Initialization Code - form_init.c"
.XS
              \*(SN  Form Information Structure Initialization Code
.XE
.sp
.PP
In addition to the Form Information Structure in the "form_info.h" file
that \fBconductor\fP generates, is the C code to initialize that structure 
that \fBconductor\fP creates in the file "form_init.c".  
The code is simple and straightforward -
it simply goes sequentially through the Form Information
structure specified in "form_info.h", and initializes values
to defaults provided, or to NULL or 0 where appropriate.
The code generated for our example user interface 
description in "form_init.c" is not included here, but can be found
in the \f(CWKHOROS_HOME/manual/conductor/examples\fP directory, 
in case the reader would like to refer to it there.  
The routine generated is called:
.sp
\f(CW
_xvf_init_Master(formptr, forminfo)
.br
xvf_form *formptr;
.br
Master *forminfo;
\fP
.sp
.PP
It should be called once only at the beginning of the
application program, to initialize (in our case) the "Master"
Form Information Structure properly.
.sp 2
.NH 3 "Extraction Code - form_info.c"
.XS
              \*(SN  Extraction Code
.XE
.sp
.PP
The third file generated by \fBconductor\fP is "form_info.c".  In the file
"form_info.c" is the C code to extract information from the user interface,
and fill in the current values of each
Form Information, Subform Information, and Pane Information 
structure that \fBconductor\fP generates in the file "form_info.h".
The code is simple and straightforward - however, instead of one
huge routine to fill in all the values of the Form Information 
structure (as is the case in the initialization code), the code
to get current information from the forms is modular.  
The code generated for our example is not included here - 
instead, a brief summary of the routines is given.  However, if the 
reader would like to refer to the code in its entirety, it can be found
in the "examples" directory.
.sp
NOTE:  the routines generated in "form_info.c" are TOTALLY dependent
on the positioning of lines in the UIS.  Adding a line or
deleting a line in the UIS implies that you MUST call
\fBconductor\fP again, to re-create these routines and be sure that
they will give correct results.
.sp
In our example, automatically generated are the following routines: 
.sp
.XP
*     One "_xvf_get_XXX" routine where XXX is the name of the Form
Information structure, provided as the variable on the (-F)
Startform line of the user interface description file;  
passed in are the pointer to the form tree, and a pointer to
the XXX Form Information Structure.  In our example:
.sp
\f(CW
		_xvf_get_Master(formptr, forminfo)
.br
		xvf_form *formptr;
.br
		Master *forminfo;
.sp
\fP
.PP
Regardless of the \fIlevel of extraction\fP (see the next section), this routine
MUST be called by the application program to extract the appropriate information
from the master form.  According to the current values of Master, the
application might take immediate action, or, based on which of the 
"Master.Subform1_selected" or "Master.Subform2_selected" variables
has a value of 1 (TRUE), might direct program flow
to a sub-driver for that subform.
.sp
.XP
*     One "_xvf_get_YYY" routine for EACH Subform Information 
structure, where YYY is the name of the Subform Information
structure, provided as the variable on the (-M) StartSubForm
line of the user interface description file;  passed in are
the pointer to the form tree, and a pointer to the YYY
Subform Information Structure.  In our example:
.sp
\f(CW
	_xvf_get_SubForm1(formptr, subforminfo)
.br
	xvf_form *formptr;
.br
	Master_SubForm1 *subforminfo;
.sp  
	_xvf_get_SubForm2(formptr, subforminfo)
.br
	xvf_form *formptr;
.br
	Master_SubForm2 *subforminfo;
\fP
.sp  
If the \fIlevel of extraction\fP is 1 (see next section), these routines will 
be called automatically from the previously-mentioned "_xvf_get_Master()"
routine.  Otherwise, calls to these routines MUST be made by the application
program in order to update the Subform Information structure in question, before
the structure may be used. Then, according to the current values of the desired
Subform Information structure, the application might take immediate action, 
or, based on which of the "pane_selected" flags is TRUE, might re-direct flow
to a sub-driver for that pane.
.sp
.XP
*     One "_xvf_get_ZZZ"  routine for EACH Pane Information structure
in EACH Subform Information structure, where ZZZ is the name 
of the Pane Information structure, provided as the variable on 
the (-P) StartPane line of the user interface description file;
passed in are the pointer to the form tree, and a pointer to 
the ZZZ Pane Information Structure.  In our example:
.sp
\f(CW
	_xvf_get_input(formptr, paneinfo)
.br
	xvf_form *formptr;
.br
	SubForm1_input *paneinfo;
.sp  
	_xvf_get_output(formptr, paneinfo)
.br
	xvf_form *formptr;
.br
	SubForm1_output *paneinfo;
.sp  
	_xvf_get_transforms(formptr, paneinfo)
.br
	xvf_form *formptr;
.br
	SubForm2_transforms *paneinfo;
\fP
.sp  
.PP
If the \fIlevel of extraction\fP is 1 or 2 (see next section), 
\fI_xvf_get_input()\fP and \fI_xvf_get_output()\fP will be called 
automatically from \fI_xvf_get_Subform1()\fP, while \fI_xvf_get_transforms()\fP
will be automatically called from \fI_xvf_get_Subform2()\fP.
Otherwise, calls to these routines MUST be made by the application
program in order to update the Pane Information structure in question, before
the structure may be used. Once the appropriate routine has been called to get
current information from its corresponding pane in the user interface, the
application may inspect the current information as desired, and act accordingly.
.PP
While the modularity of the generated code in "form_info.c"
is perhaps more pleasing to the eye than straightline code to fill 
in the entire Form Information structure at once would be (like the 
automatically generated initialization code), there is a more practical
reason for the modularity in this case. This reason is that \fBconductor\fP 
needs provide to the user application either more or less control over 
the gathering of information from the forms, as is suitable to the particular
application in question.  The more control that is given to the application 
program in information extraction, the more efficient the extraction process
can be. The application programmer may decide, at the time 
when \fBconductor\fP is run, how much control they would like to have over the 
extraction of information from the forms.  
.sp 2
.NH 4 "Level 1 Extraction"
.XS
                          \*(SN  Level 1 Extraction
.XE
.sp
.PP
Note that in our example, we entered (1) for the Level of Extraction.
This implies that we want the generated \fI_xvf_get_Master()\fP routine
to get ALL the form information for us, at one time.  
In other words, when we call \fI_xvf_get_Master()\fP, we will expect to 
get the current information from the master form, as well as from 
both subforms and all the panes on each.  We, as the application 
programmers, will make only one call to get information from the 
graphical user interface, 
and that call will be to \fI_xvf_get_Master()\fP.  This implies that a level
1 extraction gives the xvroutine the least amount of control over
information extraction.
.sp
Thus, in "_xvf_get_Master()", the reader will note two calls:
\f(CW
.br
	_xvf_get_SubForm1(formptr, forminfo->SubForm1)  and
.br
	_xvf_get_SubForm2(formptr, forminfo->SubForm2)
.sp
\fP
And, in "_xvf_get_SubForm1", the reader will see two more calls:
\f(CW
.br
	_xvf_get_input(formptr, subforminfo->input)   and 
.br
	_xvf_get_output(formptr, subforminfo->output)
.sp
\fP
While in "_xvf_get_SubForm2", there is a call to:
.br
\f(CW
	_xvf_get_transforms(formptr, subforminfo->transforms) 
.sp
\fP
.PP
There are both pros and cons to a Level 1 Extraction.  On one hand,
it is the most simple for the application program: only one
call to \fI_xvf_get_Master()\fP is necessary, and all possible information
is then filled out.  It is best for small xvroutines
that do not use a master form (implying the use of only one subform).  
Application programs that have a single subform with a single pane should
\fIalways\fP use a Level 1 Extraction.  
.PP
CAUTION:  when using a Level 1
Extraction on a UIS file that has a single subform with a single pane, 
\fIDON'T FORGET to set the selected fields on the startsubform (-M) line
and the startpane (-P) line to TRUE (1).\fP  If the \fIselected\fP fields on 
either of these lines is set to FALSE (0), the extraction routines created by 
\fBconductor\fP WILL NOT WORK!
.PP
With application programs that use more than one subform, however, 
a Level 1 Extraction becomes increasingly inefficient.  
Consider the fact that although one is almost always interested ONLY 
in the information on a single subform at any given time, a Level 1 
Extraction implies a great deal of unnecessary computing time which 
must be spent filling out the information on the other subforms, in
spite of the fact that that information will most likely not be used.
.sp 2
.NH 4 "Level 2 Extraction"
.XS
                          \*(SN  Level 2 Extraction
.XE
.sp
.PP
A Level 2 Extraction is a compromise between efficiency & convenience 
for the application programmer.  It provides an intermediate amount of
control over the information extraction process to the application program.
If a Level 2 Extraction had been done in  our example, the following would 
have happened:
.sp
 	The code in \fI_xvf_get_Master()\fP" would NOT include the calls:
\f(CW
.br
               	_xvf_get_SubForm1(formptr, forminfo->SubForm1)\fP  or
.br
\f(CW
               	_xvf_get_SubForm2(formptr, forminfo->SubForm2)
\fP
.sp
	However,  \fI_xvf_get_SubForm1()\fP would STILL call
.br
\f(CW
                    _xvf_get_input(formptr, subforminfo->input)\fP   and
.br
\f(CW
               	_xvf_get_output(formptr, subforminfo->output)
\fP
.sp
       	And in \fI_xvf_get_SubForm2()\fP, there WOULD still be a call to:
.br
\f(CW
               	_xvf_get_transforms(formptr, subforminfo->transforms)
\fP
.br
.PP
So, the application program would now have to make three calls:
First, a call to \fI_xvf_get_Master()\fP, to get information from the master
form.  If a flag corresponding to a
master action button showed that the user had clicked on that master action
button, the application program might act immediately. Otherwise, depending on 
which of the "Master.SubForm1_selected" or "Master.SubForm2_selected" 
flags was 
TRUE, the xvroutine would then call either \fI_xvf_get_SubForm1()\fP
would extract the information from Subform1, or  \fI_xvf_get_SubForm2()\fP
to get information from Subform2.
.PP
While more efficient than a Level 1 Extraction, we will still get 
information that we probably don't need:  If there is more than one 
pane on a subform, we will be getting the information for EACH pane on
that subform, regardless of whether will will need it or not.  
And, of course, there is a time cost associated with getting that 
unnecessary information.  
Thus, a Level 2 Extraction is best with subforms that have only a 
small number of panes on each; however, the number of subforms 
involved is no longer an efficiency consideration, as it is in a 
Level 1 Extraction.  
.sp 2
.NH 4 "Level 3 Extraction"
.XS
                          \*(SN  Level 3 Extraction
.XE
.sp
.PP
The Level 3 Extraction provides the most efficient method of information
extraction from the forms;  it also implies the most control over the information
gathering process by the application program.  If a Level 3 Extraction had been 
done in our example, the following would have happened:
.sp
	The code in \fI_xvf_get_Master()\fP would NOT include the calls:
\f(CW
.br
          _xvf_get_SubForm1(formptr, forminfo->SubForm1)  or
.br
          _xvf_get_SubForm2(formptr, forminfo->SubForm2)
.sp
\fP
	And the code in \fI_xvf_get_SubForm1()\fP and \fI_xvf_get_SubForm2()\fP 
would NO LONGER include calls to any of:
.sp
\f(CW
          _xvf_get_input(formptr, subforminfo->input),
.br
          _xvf_get_output(formptr, subforminfo->output)
.br
          _xvf_get_transforms(formptr, subforminfo->transforms) 
\fP
.sp
.PP
Now, it is the responsibility of the xvroutine to make
ALL information extraction calls.  As usual, a call must be made to 
\fI_xvf_get_Master()\fP.  Then, depending on which of the 
"Master.SubForm1_selected" or "Master.SubForm2_selected" flags was set
to TRUE, either \fI_xvf_get_SubForm1()\fP would be called to get the
information from Subform1, or  \fI_xvf_get_SubForm2()\fP would be called to
get info from Subform2. If the pertinent Subform Information structure 
indicated that a subform button had been clicked on, the xvroutine
should take action accordingly. Otherwise, one of \fI_xvf_get_input()\fP, 
\fI_xvf_get_output()\fP, or \fI_xvf_get_transforms()\fP
would have to be called to get the necessary information 
off the currently active pane. 
.PP
For example, only if 
master_info->SubForm1->input_selected flag was TRUE would we call 
\fI_xvf_get_input(formptr, subforminfo->input)\fP.  This is a much more 
efficient
approach to the extraction of information from the forms. We only get the
information that we need, when we need it.  If the size of the forms used 
is large, the number of subforms and panes numerous, one will find 
the increased efficiency provided by a level 3 implementation may be several
orders of magnitude.
.PP
To summarize, since the [-b] flag is provided to create an appropriate
skeleton driver according of the level of extraction, none of the three 
implementations is actually more work than any of the others for application
\fIprogrammer\fP; the necessary extraction calls will be placed correctly 
in the generated driver in any level implementation.  
We only emphasize here the three levels of implementation so that the 
application programmer using \fBconductor\fP will know how to utilize the
[-l {levels} ]  flag to generate code most suitable to their own application, 
and, once it is generated, will have a clear understanding of how it works.  
.sp 2
.NH 3 "The Skeleton Driver - form_drv.c"
.XS
              \*(SN  The Skeleton Driver
.XE
.sp 2
.PP
The skeleton application program generated by using \fBconductor\fP with the
[-b] flag is created in "form_drv.c".  The reader is encouraged
to look over the generated code at this time, which can be found in
\f(CWKHOROS_HOME/manual/conductor/example/form_drv.c\fP.  
The code generated is modular; there are sub-drivers generated for each 
subform, and subordinate sub-drivers generated for each pane.   
The application programmer must, of course, put
in the critical code to respond to each of the user's possible actions.
.PP
Note that the skeleton driver is automatically generated for conjunctive use
with \fBghostwriter\fP, and because of this, the driving routine will be given
a name "run_XXX", where XXX is the variable name specified on the (-F) StartForm
line of the UIS.  This routine will be substituted for the library routine 
in the "lxvroutine.c" file generated by \fBghostwriter\fP for 
the command line version of the same program.  
.PP
.NH 3 "Concluding the Use of Conductor"
.XS
              \*(SN  Concluding the Use of Conductor
.XE
.sp 2
The steps for integrating the code generated by \fBconductor\fP with that 
generated by \fBghostwriter\fP have already been explained in detail earlier 
in this chapter, so we will not repeat them again.  After these simple 
modifications, it is time to add the functionality to your xvroutine, by
adding code to the skeleton driver (now distributed between the files
"run_xvroutine.c" and "lxvroutine.c").  Simply look for the comments saying, 
\f(CW/* PUT YOUR CODE HERE */\fP, that will prompt you to position your code 
correctly, in response to the user's input to the forms.  
.PP
It is important that in any master form, or subform driver, 
that you \fIalways check for action buttons first\fP, before doing anything
else.  Consider the main user interface loop that is generated in the skeleton
driver, for instance.  Notice how the [if/else] statements always begin by
checking for any action buttons that may appear on the master form.  There 
is a good reason for this:  remember that at any time during the execution 
of an xvroutine, it is possible that at least one subform is mapped, and thus
this subform will be considered to be selected.  However, the user's input
may have come from the master form, and not from the subform that is currently
selected.  Thus, if you check whether a subform is selected (and call the
appropriate subform driver) before you check for a master action button, 
you will never get the action button on the master to "register" when the 
user has a subform mapped.  Similar arguments apply for subform drivers 
(usually there is at least one pane selected at any time).
.PP
At this time, you should continue with the steps for writing & installing
programs as detailed in Chapter 1 on Writing Programs of the Khoros User's 
Manual.
.PP
Once your xvroutine has had its first design iteration, you  
may at any time wish to change the GUI slightly, adding selections,
deleting buttons, etc.  This presents no problem.  Simply make the desired
changes to the user interface description file, and re-run \fBconductor\fP, 
\fIwithout using the [-b] flag.\fP  It is important to remember that while 
default values, position strings, labels, lower and upper bounds of integers 
and floats, etc. may be changed without affecting the automatically-generated 
code, \fIany time a UIS line is added, deleted, or moved,\fP \fBconductor\fP 
\fImust be run again.  Failure to re-run\fP \fBconductor\fP \fIafter a change 
in the UIS will cause a long series of error messages from the \fIxvforms\fP 
parsing routines to pop up when one attempts to execute the xvroutine.\fP
.sp 3
.sp 2
.NH 1 "USE OF CONDUCTOR BY EXISTING KHOROS PROGRAMS"
.XS
\s12\*(SN  USE OF CONDUCTOR BY EXISTING KHOROS PROGRAMS
.XE
.sp 2
.PP
The majority of the major application programs in the Khoros System are
xvroutines.  These all have code generated by \fBconductor\fP (an important 
exception to this rule is \fBcantata\fP, which will be briefly discussed later).
Some Khoros programs are located with the xvroutines, but do not have a
graphical user interface (being non-interactive), and thus are not considered
xvroutines, but graphic hybrid routines.  These, including the \fBputimage, 
iconimage, xverror, xvhelp,\fP and \fBxvviewer\fP programs, do not use 
\fBconductor\fP.  The xvroutines which had \fBconductor\fP to aid in their 
creation and maintenance include the following programs:
.sp
.B
\(bu 
animate
.br
\(bu
composer
.br
\(bu
editimage
.br
\(bu
preview
.br
\(bu
viewimage
.br
\(bu
warpimage
.br
\(bu
xprism2
.br
\(bu
xprism3
.sp
.PP
Each of the application programs listed above uses the \fIxvforms\fP graphical
user interface; in each case, \fBconductor\fP was used to generate the 
Form Information structure needed to get information from the graphical 
user interface, to initialize that structure on start-up, and to extract 
the information from the GUI during the course of execution.  
.PP
Since each of these xvroutines listed above also needed a command line 
user interface,
the creation of each of these programs (with the exception of \fBxprism2\fP 
and \fBxprism3\fP, for reasons we will not discuss here), was also aided by
\fBghostwriter\fP.  Thus, each has a *.c, *.h, and a *.1 file (where "*" is
the name of the program), which was originally created by \fBghostwriter\fP.
Some have a library file named l*.c, the body of which was originally generated 
by \fBconductor\fP in the file "form_drv.h".  For those, the "form_drv.c"
file was modified as needed, had its name changed to "l*.c", and is now used 
as the library call for the application program.  In addition, there are
example programs that may be found in \f(CWKHOROS_CONTRIB/src/examples\fP.
We recommend these for reference as examples of how \fBconductor\fP and 
\fBghostwriter\fP can be used in conjunction to create an xvroutine with both 
a CLUI and a GUI.  In addition, these examples demonstrate use of the 
\fIxvgraphics\fP and \fIxvdisplay\fP libraries.
.PP
As mentioned earlier, the only "xvroutine" in the Khoros System that does
NOT use \fBconductor\fP is the \fBcantata\fP visual language.  In contrast 
to the other xvroutines previously, \fBcantata\fP is \fIinterpretive\fP.  
That is, it interprets input to its GUI \fIon its own\fP, without any 
intervening code that was automatically generated by \fBconductor\fP;  
the writers of the \fBcantata\fP software were required to have an intimate 
understanding of the internals of the \fIxvforms\fP library in order to 
create the code that drives the GUI of \fBcantata\fP.  In general, an attempt 
at this method of programming under the Khoros system is \fIvery strongly 
discouraged\fP -- any use of non-public (undocumented) library routines is 
unwise, as these routines may change at any time without notice.  
The \fBcantata\fP program, however, by its very nature, must be an exception 
to the rule.  
.PP
The biggest drawback to the use of \fBconductor\fP is that each time lines 
are added to or deleted from the UIS file of an application program, 
\fBconductor\fP must be re-run to regenerate the "form_init.c", "form_info.c",
and "form_info.h" files; the xvroutine must then be re-compiled before
use.  In general, this is not a problem for programmers 
working in cooperation on an application program.  However, by definition,
the \fBcantata\fP visual language program must allow many people to 
\fIindependently\fP and \fIsimultaneously\fP add programs at will, without
cooperation with, (or even knowledge of) each other. If \fBcantata\fP
had been developed using \fBconductor\fP, this would have quickly 
led to disaster!  
.PP
You should realize, however, that \fBcantata\fP is the exception, and
not the rule, for application programs under the Khoros system.  For 
all other application programs that are to use the graphical user interface,
\fBconductor\fP is an invaluable time-saving tool.  It ensures modular code,
and consistency with other xvroutines in the Khoros System, as  
well as guaranteeing correct and efficient initialization and extraction 
of information from the graphical user interface.  With only a little practice,
use of the \fBconductor\fP program will become trivial, and the application
programmer will be freed to concentrate on other, more important things -
specifically, the functionality of the application program!
.sp
