.cc
.page size 55
.no number
.nf .nj .lm 5 .rm 75

.sk 1
.sk 1
.sk 1
.sk 1
.sk 1
.sk 1
.sk 1
.sk 1

.c;USING FPAINT SCREENS: AN EXAMPLE APPLICATION

.sk 4
.c;John Sinclair
.c;Mark Geib
.c;Inland Steel Company
.c;10-Oct-1986

.number 1
.pg
.nf .nj
Using FPaint Screens - general considerations

.sk 2 .f .j
.i5;FPaint builds a package of FORTRAN subroutines that may be considered
the abstraction of a data entry screen. Each screen has the following
characteristics:

.sk 1 .nf .nj .lm 10
- A five character name (#referred to below as <NAME>#)
.sk 1
- A specific height (in rows) and width (in columns)
.sk 1
- A number of fixed text fields
.sk 1
- A number of data fields of varying characteristics
.sk 1
- A screen help line
.sk 1

.sk 2 .f .j .lm 5
In addition, the following operations may be performed on a screen:

.sk 1 .nf .nj .lm 10
- Clear        - clear the area occupied by the screen
.sk 1
- Display Text - display screen text
.sk 1
- Display Data - display screen data field contents
.sk 1
- Edit         - begin edit of screen data fields
.sk 1
- Validate     - validate all screen data fields

.sk 2 .f .j .lm 5
.i5;Using an FPaint screen successfully therefore depends on invoking the
above routines properly and in the correct order. The first task is
thus to examine each routine in detail.

.sk 2
FPaint Screen Operations - A Detailed Description

.sk 2 .nf .nj
Clear

.sk 1 .f .j
The Clear operation is invoked as

.sk 1 .nf .nj
call <NAME>Clear( Row, Col )

.sk 1 .f .j .lm 10
where Row and Col give the origin of the upper left of the screen
in rows and cloumns on the CRT relative to the upper left corner.

.sk 1 .lm 5
Clear causes the rectangular area of the CRT occupied
by the screen to be erased. The given area extends from rows "Row"
to "Row"+Height and from columns "Col" to "Col"+Width.

.pg .nf .nj
Text Display

.sk 1 .f .j
The Text Display operation is invoked as

.sk 1 .nf .nj
call <NAME>TextDsp( Row, Col )

.sk 1 .f .j .lm 10
where Row and Col give the origin of the upper left of the screen
in rows and cloumns on the CRT relative to the upper left corner.

.sk 1 .lm 5
Text Display causes all screen text fields to be displayed
on the CRT relative the the screen origin.


.sk 2 .nf .nj
Data Display

.sk 1 .f .j
The Data Display operation is invoked as

.sk 1 .nf .nj
call <NAME>DataDsp( Row, Col, First, Last, {Data} )

.sk 1 .f .j .lm 10
where Row and Col give the origin of the upper left of the screen
in rows and cloumns on the CRT relative to the upper left corner,
First is the first field to be displayed, Last is the last field
to be displayed and {Data} is the list of variables that correspond
to the FPaint data fields.

.sk 1 .lm 5
Data Display causes the current value of all specified screen data
fields to be displayed on the CRT relative the the screen origin. Note
that all data should be initialized prior to invoking this routine.


.sk 2 .nf .nj
Edit

.sk 1 .f .j
The Edit operation is invoked as

.sk 1 .nf .nj
call <NAME>Edit( Row, Col, First, Last, CurrentField, TermKeys,
                 {Data}, Next, Previous, Refresh, Exit, LastKey )

.sk 1 .nf .nj .lm 10
where,
.sk 1 .f .j
Row and Col give the origin of the upper left of the screen
in rows and cloumns on the CRT relative to the upper left corner;
.sk 1
First is the first field to be edited and Last is the last field
to be edited;
.sk 1
CurrentField is, on input, the field at which editing is to begin
and, on output, the last field edited;
.sk 1
TermKeys is a 30 element integer*2 array to be discussed later;
.sk 1
{Data} is the list of variables that correspond to the FPaint
data fields;
.sk 1
Next is a termination flag that indicates a carraige return or down
arrow was pressed during edit of the last field;
.sk 1
Previous is a termination flag that indicates an up arrow was pressed
during edit of the first field;
.sk 1
Refresh	is a termination flag that indicates the screen image should be
refreshed;
.sk 1
Exit is a termination flag that indicates the edit is complete;
.sk 1
LastKey is the last key typed by the operator.


.sk 1 .lm 5
The Edit operation initiates data entry or edit of all specified
data fields beginning with the current field. This operation
continues until terminated by the operator.

.sk 1
Edit is terminated by any one of the following events:

.sk 1
.lm 10
.i-2;- The operator presses a carriage return or a down arrow
while editing the last field of the screen. In this case, Next is set,
which, for multi screen applications, means "go to the next screen".

.sk 1
.i-2;- The operator presses an up arrow while editing
the first field of the screen. In this case, Previous is set, which,
for multi screen applications, means "go to the previous screen".

.sk 1
.i-2;- The operator presses control R. In this case, Refresh is set, which
means "refresh the entire screen image". This may be necessary if, during
data entry, a system message covers up an area of the screen.

.sk 1
.i-2;- The operator presses control Z. In this case, Exit is set, which
means "data entry/edit is complete".

.sk 1
.i-2;- The operator presses a programmer defined termination key
(#named TermKeys in the Edit parameter list#). No flags are set but LastKey
holds the ASCII value of the pressed key.

.sk 2 .nf .nj
Validate

.sk 1 .f .j
The validate operation is invoked as

.sk 1 .nf .nj
call <NAME>Validate( First, Last, {Data}, Valid, FieldNumber )

.sk 1 .f .j .lm 10
where First is the first field to be displayed, Last is the last field
to be displayed and {Data} is the list of variables that correspond
to the FPaint data fields.

.sk 1 .lm 5
Validate performs a validation check on all specified data
fields. If any field is invalid, Valid is set to .false.
and FieldNumber holds the index of the offending data field.
If all fields are valid, Valid is set to .true. and FieldNumber
is undefined.


.sk 2 .lm 5
Programmer Defined Termination Keys

.sk 2
.i5;As mentioned above, a special set of keys, called termination keys,
may be defined by the programmer. During an edit operation, pressing
one of these keys causes the edit to terminate. A thirty element
integer array contains the termination key information.

.sk 1
.i5;As if to complicate things, two types of termination keys may reside
in the array simultaneously as separate lists. These two types will be
refered to as edit termination keys and immediate termination keys.

.sk 1
.i5;When an edit termination key is pressed, FPaint checks the validity
of the current field being edited. If valid, the edit terminates,
otherwise an error message is issued and edit continues.

.sk 1
.i5;An immediate termination key, as its name implies, causes an immediate
and unconditional termination of the edit. A possible use for
such a device might be that of popping up a help screen to give an
operator additional assistance upon demand. Another obvious use
includes the aborting of an operation.

.sk 1
.i5;The result of immediate termination is slightly different depending
on whether or not the current field is numeric.
If, during the edit of a numeric data field, an immediate termination key
is pressed, the edit is, in effect, aborted and the partially edited value
lost. A non-numeric data field retains the partially edited value.

.sk 1
Important: It is the programmers responsibility to
reenter the edit routine after processing an immediate termination
key without changing the edit state.

.sk 1
.i5;The structure of the termination key array is best described by example.
Figure 1 shows the logical contents of the termination key array.
In addition, an example is given below.

.sk 2 .nf .nj
Example 1  A possible array of termination keys

.sk 1
TermKeys(1) = 4           { 4 edit termination keys }
TermKeys(2) = 1           { _^A }
TermKeys(3) = 141         { PF1 }
TermKeys(4) = ichar('?')  { ? }
TermKeys(5) = 4           { _^D }

.sk 1
TermKeys(6) = 2           { 2 immediate termination keys }
TermKeys(7) = 142         { PF2 }
TermKeys(8) = 143         { PF3 }

.sk 1 .f .j
Appendix III contains the numeric values of function and keypad keys.

.sk 2 .lm 5 .nf .nj
Integrating the Operations

.sk 2 .f .j
.i5;Having fully described each screen operation, the next objective
is the synthesis of a working FPaint screen. In general, the following
logic is employed:

.sk 1
.nf .nj .lm 10
- Choose an appropriate origin for the screen.
.sk 1
- Set First and Last to define the set of data fields to be
  operated upon. This provides the capability to display, edit
  or validate a single field or a specific subset of fields.
  Setting First to 1 and Last to 100 will cause all fields to
  be included in a given operation.
.sk 1
- Define all termination keys.
.sk 1
- Initialize all screen data fields.
.sk 1
- Clear the screen.
.sk 1
- Display the screen text.
.sk 1
- Display the screen data.
.sk 1
- Perform the edit operation starting with a given field number.
  On return from the edit, process the termination flags and
  keys.
.sk 1
- Insure that all data is valid ( If not, repeat the edit
  operation starting with the invalid field ).

.sk 1 .lm 5
Rather than elaborating on the above, a specific example will be
considered in detail.

.sk 2
Example Program Description
.sk 2
.f .j
.i5;Appendix I contains the listing of a program that incorporates two FPaint
screens to perform operator input. It is based on a system that
is used to acquire data from a device capable of measuring the surface
roughness of a steel specimen. The example presented here serves merely
to illustrate the use of FPaint screens in an application; the routine
that would perform any useful work is, of course, a stub.

.sk 1
.i5;Presumably, an operator runs the program to measure the roughness
of a group of replicate specimens. Data entry is made at two levels.
First, information common to all specimens is entered through the
FPaint screen named Group. Then, before each specimen is processed, the
specimen ID and orientation is entered through the FPaint screen
named Spec.

.sk 1
.i5;The operator may enter individual specimen information repeatedly
until all replicates of a given group have been processed. The choice
is then made either to exit the program or repeat the process with
another group of specimens.

.sk 1
.i5;Figure 2 outlines the program logic and processes.


.sk 3
.nf .nj
The FPaint Screens

.sk 2 .f .j
.i5;Before considering the details of the FPaint interface, it
is worthwhile to examine the screens individually.

.sk 1
.i5;Group, the specimen group screen, is shown in Figure 3 and Spec, the
individual specimen screen in figure 4.

.sk 1
.i5;The final composite screen (from the operator's point of view) includes
Group with the upper left corner origin at (1,1) and Spec with
origin at (11,39). This is shown in figure 5.

.sk 2
A Detailed Examination of the Example

.sk 2
.i5;As mentioned previously, Appendix I contains the listing of an example
program, Profil.For. The following is detailed examination of the
FORTRAN source code.

.sk 1
.lm 5
Section 1 contains declarations for the Group screen variables.
Notice the similarity to the declarations given in the Group auxillary
file listed in Appendix II. Also note that "Description" is a three
element array.

.sk 1
Section 2 contains declarations for the Spec screen variables.
Notice the similarity to the declarations given in the Spec auxilary
file listed in Appendix II.

.sk 1
Section 3 contains declarations for local variables.

.sk 1
Section 4 serves to initialize constants and variables. Notice
that screen variables must be initialized in the application.

.sk 1
Section 5 deserves special attention.

.sk 1
.i5;TTYinit must be called before any FPaint operation is invoked. This
is especially true for a VAX hosted system. TTYinit initializes both the
display and a package of display routines. It may also be called during
program exit to clean up the display state.

.sk 1
.i5;EchoOff should be called in DEC-10 environments. It will eliminate any
problems associated with echoed type ahead.

.sk 1
.i5;KpdOn may be called to place the terminal in keypad application mode.
Note that it is not necessary in this application.

.sk 1
Section 6: First field to edit for Group screen is 3.

.sk 1
Section 7: Clear the Group screen.

.sk 1
Section 8: Display the Group screen text ( figure 6 ). Note that
"description" is an array that contains three FPaint fields.

.sk 1
Section 9: Display the Group screen data ( figure 7 ).

.sk 1
Section 10: Start of loop "repeat until no more specimen groups".

.sk 1
Section 11: Edit the Group screen ( figures 8 and 9 ) starting with
field three. Process the termination state as follows:

.sk 1 .lm 10
[A]
if the operator pressed PF1 ( abort ) then turn off the key pad,
clear the screen, and stop program;

.sk 1
[B]
if "go to next screen" ( i.e. Next is set ) then simply wrap to
field number three of the same screen;

.sk 1
[C]
if "go to previous screen" ( i.e. Previous is set ) then simply
wrap to the last field;

.sk 1
[D]
if "screen needs to be refreshed" goto 100 to clear, redisplay,
and continue the edit of Group.

.sk 1
[E]
if "data entry/edit is not complete" goto 300 to continue the edit.

.sk 1 .lm 5
Section 12: Validate the Group screen. If any field is
invalid then continue the edit at that field number.

.sk 1 .lm 5
Section 13: First field to edit for Spec screen is 1.

.sk 1
Section 14: Start of loop "repeat until no more specimens".

.sk 1
Section 15: Clear the Spec screen ( figure 10 ).

.sk 1
Section 16: Display the Spec screen text ( figure 11 ).

.sk 1
Section 17: Display the Spec screen data ( figure 12 ).

.sk 1
Section 18: Edit the Spec screen ( figure 13 ) starting with
field one. Process the termination state as follows:

.sk 1 .lm 10
[A]
if "go to next screen" ( i.e. Next is set ) then simply wrap to
field number one of the same screen;

.sk 1
[B]
if "go to previous screen" ( i.e. Previous is set ) then simply
wrap to the last field;

.sk 1
[C]
if "screen needs to be refreshed" then clear and redisplay the Group screen
and then goto 400 to clear, redisplay, and continue the edit of Spec.

.sk 1
[D]
if "data entry/edit is not complete" goto 500 to continue the edit.

.sk 1 .lm 5
Section 19: This is the call to some routine that would utilize the
FPaint input and perform some useful work. The routine is a stub in this
example ( see the listing of Subs.For in Appendix I ).

.sk 1
Section 20: Ask operator if more specimens are to be tested for
this group ( see the listing of Subs.For in Appendix I ).

.sk 1
Section 21: If more specimens for this group then clear and
redisplay the group screen (#just for looks#). As the loop repeats
the specimen screen will again be overlayed on the group screen.

.sk 1
Section 22: End of loop "repeat until no more specimens".

.sk 1
Section 23: Ask operator if more groups of specimens are to be tested
( see the listing of Subs.For in Appendix I ).

.sk 1
Section 24: End of loop "repeat until no more specimen groups".

.sk 1
Section 25: Key pad off, clear screen, and terminate program.

.sk 2 .lm 5 .f .j
Custom Validation of FPaint Data Fields

.sk 2
.i5;Appendix I contains a listing of the file Subs.For, a collection of
subroutines called by the example program. Of interest to this
discussion is the routine ValScr.

.sk 1
.i5;Whenever the edit of an FPaint data field is completed (#either as
a result of moving to another field or terminating the edit#),
validation is performed as prescribed when the field was created.
In addition, if the data field passes the FPaint validation, the
subroutine ValScr is called in order that custom validation may
be performed by the application.

.sk 1
.i5;ValScr is present in the standard FPaint library as a stub that
sets the Valid flag true, thus imposing no additional validation
constraints on the data.

.sk 1
.i5;If a subroutine named ValScr is included in the application, it will
supersede the library stub, enabling custom validation to be performed.
See the example in Subs.For for a description of the parameters.
The logic of any such custom routine should always be similar to the
pseudocode given below:

.sk 1 .lm 7
if Name is equal to the screen to be validated then

.sk 1 .lm 10
if Field is equal to the field to be validated then 

.sk 1 .lm 13
check the value of Intg, Rl, or Str depending on the field type
( which is known a priori )

.sk 1
if the value is OK then
.nf .nj
  Valid = .true.
else
  Valid = .false.
  display some appropriate error message via
  the routine ErrMsg
end if

.sk 1 .lm 10
end if

.sk 1 .lm 7
end if

.sk 1 .lm 5 .f .j
(#Note the use of the "<Name>Ind" function in the example, e.g. GroupInd.
  This function maps the field name to the field number. Since field
  numbers may change whenever fields are added to or deleted from an
  FPaint screen, this field index function should be used when refering
  to a particular FPaint field#).

.sk 2 .lm 5 .f .j
FPaint From the User's Viewpoint

.sk 2
.i5;Up to this point, the description of FPaint has been programmer oriented.
The application user, of course, is interested in the ease with which
data may be entered and edited.

.sk 1
.i5;Editing is performed at two levels. Screen editing involves moving
from one field to another. This is accomplished with the keys described
below.

.sk 1 .lm 10 .nf .nj
Up arrow        - Move to the previous data field.
Down arrow      - Move to the next data field.
Carriage Return - Move to the next data field.

.sk 1 .lm 5 .f .j
.i5;Editing may also occur at the individual field level. The keys listed
below perform field edit functions.

.sk 1 .lm 10 .nf .nj
Control B       - Move to beginning of field
Control E       - Move to end of field
Tab             - Move to next word
Control X       - Move to previous word
Control W       - Toggle insert/overwrite
Control U       - Abort edit ( restore original value )
Control J       - Delete to end of line
Control K       - Delete word

.sk 1
[Dec-10 or IBM PC]
Backspace       - delete one character backward
Delete          - delete character at cursor

.sk 1
[IBM PC]
Home            - Move to beginning of field
End             - Move to end of field
Shft Tab        - Move to previous word
Insert          - Toggle insert/overwrite


.sk 1
[Vax]
Delete          - delete one character backward
Key pad ,       - delete character at cursor
                  ( if key pad mode has been turned on )

.sk 1 .sk 1 .lm 5 .f .j
.i5;In addition to the editing keys, the function of Control R and Control Z
are worth repeating at this point. They have the meanings given below.

.sk 1 .lm 10 .nf .nj
Control R       - Refresh screen image
Control Z       - Data entry/edit is complete

.page
.literal





		                   FIGURES

.end literal
.page
.literal
	   Array Element Contents

	        1               Number of Edit Termination Keys, NE
		2		Edit Termination Key 1
		3		Edit Termination Key 2
		.			.
		.			.
		.			.
	       1+NE		Edit Termination Key NE

	      (NE+2)		Number of Immediate Termination Keys, NI
	      (NE+2)+1		Immediate Termination Key 1
	      (NE+2)+2		Immediate Termination Key 2
		.
		.
		.
	      (NE+2)+NI		Immediate Termination Key NI


                       Figure 1. Termination Key Array.


	   Program Profilometer

	   Initialize Terminal Routines

	   Display Specimen Group Information

	   Repeat

	     Get Specimen Group Information

	     Repeat

	       Display and Get Specimen Information

	       Collect and Plot Test Data

	       More Specimens?
	         if Yes then Display Specimen Group Information

	     Until No More Specimens

	     Another Specimen Group?

	   Until No More Specimen Groups

	   Program End


                       Figure 2. Main program pseudo code.
.end literal
.page
.literal




		                  APPENDIX I


                           EXAMPLE PROGRAM LISTINGS

.end literal
.page
.literal




				PROFIL.FOR





	  This is an example of a program that uses two FPaint screens.

	  An operator runs this program to measure the surface characteristics
	  of a group of replicate specimens.

	  The first screen, Group, is a	data entry screen that contains
	  specimen group information, i.e., information common to all
	  specimens.

	  The second screen, Spec, contains information unique to each
	  specimen, namely the specimen ID and orientation.

	  Note that the portion of the program that would actually do
	  some useful work is, of course, a stub.

.end literal
.page
.literal

	program Profilometer


C	SECTION 1

c---
c  variable declarations  ( Group screen )

        Integer*2 GRow, GCol, GCurField, GTermKeys(30)
        Integer*2 GNumberOfFields, GLastKey, GFirstFld, GLastFld
        Logical*1 GNext, GPrevious, GExit, GRefresh

        character* 4    Version
        character* 9    Date
        character* 6    GroupID
        character* 3    Operator
        character*65    Description(3)
        integer*2       ScanRate
        character* 6    StageVelocity


C	SECTION 2

c---
c  variable declarations  ( Specimen screen )

        Integer*2 SRow, SCol, SCurField, STermKeys(30)
        Integer*2 SNumberOfFields, SLastKey, SFirstFld, SLastFld
        Logical*1 SNext, SPrevious, SExit, SRefresh

        character* 6    SpecimenID
        character*12    Orientation


C	SECTION 3

c---
c Misc variables
	integer*2 Abort, FieldNumber
	logical*1 More, Valid

C	SECTION 4

c---
c Variable initialization

	data Abort /141/

	data GRow /1/ , GCol /1/ , SRow /11/ , SCol /39/

c---
c immediate termination on F1 key
        data GTermKeys/ 0, 1, 141, 27*0 /

        data STermKeys/ 30*0 /

        Version = '1.00'
        call Today( Date )
        GroupID = ' '
        Operator = ' '
        Description(1) = ' '
        Description(2) = ' '
        Description(3) = ' '
        ScanRate = -1
        StageVelocity = '1.0'
	SpecimenID = ' '
	Orientation = 'Transverse'


c---
c Total number of screen parameters

        GNumberOfFields = 9
	GFirstFld = 1
	GLastFld = 9

        SNumberOfFields =   2
	SFirstFld = 1
	SLastFld = 2


C	SECTION 5

c--	Initialize Terminal Routines
	call TTYinit
	call EchoOff
	call KpdOn


c--	Display Specimen Group Information

100	continue

C	SECTION 6
	GCurField = 3

150	continue

C	SECTION 7
        call GroupClear( GRow, GCol )

C	SECTION 8
        call GroupTextDsp( GRow, GCol )

C	SECTION 9
        call GroupDataDsp( GRow, GCol, GFirstFld, GLastFld
     1 , Version, Date, GroupID, Operator, Description, ScanRate
     1 , StageVelocity
     1   )

C	SECTION 10

c--	repeat
200	continue

c--	  Get Specimen Group Information

C	SECTION 11
300       call GroupEdit( GRow, GCol, GFirstFld, GLastFld, GCurField
     1   , GTermKeys, Version, Date, GroupID, Operator, Description
     1   , ScanRate, StageVelocity
     1   , GNext, GPrevious, GExit, GRefresh, GLastKey )

C	SECTION 11 [A]
	  if( GLastKey .eq. Abort ) then
	    call KpdOff
	    call ClrScr
	    stop '[Program Aborted]'

C	SECTION 11 [B]
	  else if( GNext ) then
	    GCurField = 3

C	SECTION 11 [C]
	  else if( GPrevious ) then
	    GCurField = GNumberOfFields

C	SECTION 11 [D]
	  else if( GRefresh ) then
	    goto 150

	  end if

C	SECTION 11 [E]
	  if( .not. GExit ) goto 300


c--	  Validate Specimen Group Information

C	SECTION 12
          call GroupValidate( GFirstFld, GLastFld
     1   , Version, Date, GroupID, Operator, Description, ScanRate
     1   , StageVelocity
     1   , Valid, FieldNumber )

	  if( .not. Valid ) then
	    GCurField = FieldNumber
	    goto 300
	  end if


390	  continue

C	SECTION 13
	  SCurField = 1

C	SECTION 14
c--	  repeat
400	  continue

c--	    Display and get Specimen Information

C	SECTION 15
            call SpecClear( SRow, SCol )

C	SECTION 16
            call SpecTextDsp( SRow, SCol )

C	SECTION 17
            call SpecDataDsp( SRow, SCol, SFirstFld, SLastFld
     1     , SpecimenID, Orientation
     1       )

C	SECTION 18
500         call SpecEdit( SRow, SCol, SFirstFld, SLastFld, SCurField
     1     , STermKeys, SpecimenID, Orientation
     1     , SNext, SPrevious, SExit, SRefresh, SLastKey )

C	SECTION 18 [A]
            if( SNext ) then
	      SCurField = 1

C	SECTION 18 [B]
	    else if( SPrevious ) then
	      SCurField = SNumberOfFields

C	SECTION 18 [C]
	    else if( SRefresh ) then
              call GroupClear( GRow, GCol )
              call GroupTextDsp( GRow, GCol )
              call GroupDataDsp( GRow, GCol, GFirstFld, GLastFld
     1       , Version, Date, GroupID, Operator, Description, ScanRate
     1       , StageVelocity
     1         )
	      goto 400

	    end if

C	SECTION 18 [D]
	    if( .not. SExit ) goto 500

C	SECTION 19
c--	    Collect and Plot Test Data
	    call DoTest

C	SECTION 20
c--	    More Specimens?
	    call MoreSpecs( More )

C	SECTION 21
c--	      if Yes then Display Specimen Group Information
	      if( More ) then
                call GroupClear( GRow, GCol )
                call GroupTextDsp( GRow, GCol )
                call GroupDataDsp( GRow, GCol, GFirstFld, GLastFld
     1         , Version, Date, GroupID, Operator, Description, ScanRate
     1         , StageVelocity
     1           )
	      end if

C	SECTION 22
c--	  until no more specimens
	  if( More ) goto 390

C	SECTION 23
c--	  Another Specimen Group?
	  call MoreGroups( More )

C	SECTION 24
c--	until no more specimen groups
	if( More ) goto 100

C	SECTION 25
	call KpdOff
	call ClrScr
	stop '[Normal Program Termination]'

c--	program end
	end

.end literal
.page
.literal





			         SUBS.FOR





          subroutine ValScr - An example of custom validation for the
	                      two FPaint screens.

          logical function LegalFileName - Called by ValScr.

	  subroutine DoTest - A stub. If this program really did something,
			      it would be done here.

	  subroutine MoreGroups - A routine that asks the operator if he
				  has more specimen groups. Includes an
				  example of the use of the routine Menu1.

	  subroutine MoreSpecs - A routine that asks the operator if he
			         has more specimens. Includes an example
			         of the use of the routine Menu1.

.end literal
.page
.literal





	subroutine ValScr( Name, Field, Intg, Rl, Str, Valid )

c--
c This is a custom validation routine for the profilometer program.
c
c The program uses two Fpaint screens, GROUP and SPEC. The following
c validation will be performed:
c
c
c	For the screen GROUP ( i.e. Name = 'GROUP' )
c
c	  The "GroupID" field (character) must be a
c	  valid file name.
c
c
c	For the screen SPEC ( i.e. Name = 'SPEC' )
c
c	  The "SpecimenID" field (character) must be a
c	  valid file name.
c
c--

	character*(*) Name
	integer*2 Field, Intg
	real Rl
	character*(*) Str
	logical*1 Valid


c-- functions
	logical*1 LegalFileName
	integer*2 GroupInd, SpecInd


	Valid = .true.

	if( Name .eq. 'GROUP' ) then

	  if( Field .eq. GroupInd( 'GroupID' ) ) then

	    if( .not. LegalFileName(Str) ) then
	      Valid = .false.
	      call ErrMsg( 'Group ID must be a valid file name!' )
	    end if

	  end if


	else if( Name .eq. 'SPEC' ) then

	  if( Field .eq. SpecInd( 'SpecimenID' ) ) then

	    if( .not. LegalFileName(Str) ) then
	      Valid = .false.
	      call ErrMsg( 'Specimen ID must be a valid file name!' )
	    end if

	  end if

	end if


	end


	logical*1 function LegalFileName( String )

	character*(*) String
	character*1 C
	integer*2 I, Length

	do 10 I = 1 , length( String )

	  C = String(I:I)

	  if(  ( C .lt. '0' .or. C .gt. '9' ) .and.
     1	       ( C .lt. 'A' .or. C .gt. 'Z' ) .and.
     1	       ( C .lt. 'a' .or. C .gt. 'z' )  ) then

	    LegalFileName = .false.
	    return

	  end if

10	continue

	LegalFileName = .true.

	end


	subroutine DoTest

	integer*2 Key

	call ClrScr
	call CsrPos( 3, 20 )
	call OutString( 'The test would be performed at this point' )

	call DspMessage( 'Press a key', 'to continue' )
	call FPGetChar( Key )

	end


	subroutine MoreGroups( More )

	logical*1 More, Abort
	integer*2 Item, Selection, Intense

	data Intense /2/, Normal /0/

	call EraseRegion( 23,1, 24,80 )
	call DspAttribute( Intense )
	call CsrPos( 23, 1 )
	call OutString( 'Another Specimen Group?' )
	Item = 1
10	call Menu1( 24, 'Yes   No', 'YN', Item, Selection, Abort )

 	if( Abort ) goto 10

	call DspAttribute( Normal )
	call EraseRegion( 23,1, 24,80 )

	if( Selection .eq. ichar('Y') ) then
	  More = .true.
	else
	  More = .false.
	end if

	end


	subroutine MoreSpecs( More )

	logical*1 More, Abort
	integer*2 Item, Selection, Intense

	data Intense /2/, Normal /0/

	call EraseRegion( 23,1, 24,80 )
	call DspAttribute( Intense )
	call CsrPos( 23, 1 )
	call OutString( 'Another Specimen?' )
	Item = 1
10	call Menu1( 24, 'Yes   No', 'YN', Item, Selection, Abort )

 	if( Abort ) goto 10

	call DspAttribute( Normal )
	call EraseRegion( 23,1, 24,80 )

	if( Selection .eq. ichar('Y') ) then
	  More = .true.
	else
	  More = .false.
	end if

	end
.end literal
.page
.literal






		                 APPENDIX II


                        FPAINT AUXILIARY FILE LISTINGS
.end literal
.page
.literal


Group.aux



c---
c  variable declarations

      integer*2 FirstFld, LastFld
      integer*2 Row, Col, CurField, TermKeys(30)
      integer*2 NumberOfFields
      integer*2 LastKey, FieldNumber
      logical*1 Next, Previous, Exit, Refresh, Valid

      character*  4 Version
      character*  9 Date
      character*  6 GroupID
      character*  3 Operator
      character* 65 Description(  3)
      integer*2 ScanRate
      character*  6 StageVelocity

c---
c Normal termination on F1 key
c immediate termination on F2 key
      data TermKeys/ 1, 141, 1, 142, 26*0 /

c---
c Default variable initialization
      data Version /' '/
      data Date /' '/
      data GroupID /' '/
      data Operator /' '/
      data Description(1) /' '/
      data Description(2) /' '/
      data Description(3) /' '/
      data ScanRate /0/
      data StageVelocity /' '/

c---
c Screen origin
      data Row, Col / 1, 1 /

c---
c TTY initialization
      call TTYinit
      call EchoOff
      call KpdOn

c---
c Starting edit field
      CurField = 1

c---
c Total number of screen parameters

      NumberOfFields =   9

c---
c Default limits

      FirstFld = 1
      LastFld = NumberOfFields


c---
c Clear the screen region

 10     call GROUPClear( Row, Col )

c---
c Display the Text fields

      call GROUPTextDsp( Row, Col )

c---
c Display the Data fields

      call GROUPDataDsp( Row, Col, FirstFld, LastFld
     1, Version, Date, GroupID, Operator, Description, ScanRate
     1, StageVelocity
     1 )


c---
c Edit the Data fields

 20     call GROUPEdit( Row, Col, FirstFld, LastFld, CurField, TermKeys
     1, Version, Date, GroupID, Operator, Description, ScanRate
     1, StageVelocity
     1, Next, Previous, Exit, Refresh, LastKey )



      if( Refresh ) then
          goto 10
      else if( Next ) then
          CurField = 1
          goto 20
      else if( Previous ) then
          CurField = NumberOfFields
          goto 20
      else if( .not. Exit ) then
          goto 20
      end if


c---
c Validate the Data fields

      call GROUPValidate( FirstFld, LastFld
     1, Version, Date, GroupID, Operator, Description, ScanRate
     1, StageVelocity
     1, Valid, FieldNumber )

      if( .not. Valid ) then
          CurField = FieldNumber
          goto 20
      end if

      call TTYinit
      call EchoOn
      call KpdOff

      End
.end literal
.page
.literal

Spec.aux




c---
c  variable declarations

      integer*2 FirstFld, LastFld
      integer*2 Row, Col, CurField, TermKeys(30)
      integer*2 NumberOfFields
      integer*2 LastKey, FieldNumber
      logical*1 Next, Previous, Exit, Refresh, Valid

      character*  6 SpecimenID
      character* 12 Orientation

c---
c Normal termination on F1 key
c immediate termination on F2 key
      data TermKeys/ 1, 141, 1, 142, 26*0 /

c---
c Default variable initialization
      data SpecimenID /' '/
      data Orientation /' '/

c---
c Screen origin
      data Row, Col / 1, 1 /

c---
c TTY initialization
      call TTYinit
      call EchoOff
      call KpdOn

c---
c Starting edit field
      CurField = 1

c---
c Total number of screen parameters

      NumberOfFields =   2

c---
c Default limits

      FirstFld = 1
      LastFld = NumberOfFields


c---
c Clear the screen region

 10     call SpecClear( Row, Col )

c---
c Display the Text fields

      call SpecTextDsp( Row, Col )

c---
c Display the Data fields

      call SpecDataDsp( Row, Col, FirstFld, LastFld
     1, SpecimenID, Orientation
     1 )


c---
c Edit the Data fields

 20     call SpecEdit( Row, Col, FirstFld, LastFld, CurField, TermKeys
     1, SpecimenID, Orientation
     1, Next, Previous, Exit, Refresh, LastKey )



      if( Refresh ) then
          goto 10
      else if( Next ) then
          CurField = 1
          goto 20
      else if( Previous ) then
          CurField = NumberOfFields
          goto 20
      else if( .not. Exit ) then
          goto 20
      end if


c---
c Validate the Data fields

      call SpecValidate( FirstFld, LastFld
     1, SpecimenID, Orientation
     1, Valid, FieldNumber )

      if( .not. Valid ) then
          CurField = FieldNumber
          goto 20
      end if

      call TTYinit
      call EchoOn
      call KpdOff

      End
.end literal
.page
.literal




		                  APPENDIX III


                  NUMERIC CODES FOR FUNCTION AND KEY PAD KEYS
.end literal
.page
.literal




       KEY              NUMERIC CODE

       Up Arrow            128
       Down Arrow          129
       Left Arrow          130
       Right Arrow         131

       PF1                 141
       PF2                 142
       PF3                 143
       PF4                 144

       Key Pad 0           157
       Key Pad 1           158
       Key Pad 2           159
       Key Pad 3           160
       Key Pad 4           161
       Key Pad 5           162
       Key Pad 6           163
       Key Pad 7           164
       Key Pad 8           165
       Key Pad 9           166
       Key Pad -           167
       Key Pad ,           168       	( 8 for VAX version )
       Key Pad .           169
       Key Pad Enter       170

       Back Tab            132          ( generated by ^X )
       Del Char at Cursor  127		( generated by Del or Backspace )
       Del Char Backward     8		( generated by Backspace or key pad , )



	For IBM PC

	Keypad Keys

	Insert		    23	(^W)
	Delete		   127	(Del)
	Home		     2	(^B)
	End		     5	(^E)
	PgUp		   133
	PgDn		   134


	Function Keys	Un-Shifted	Shifted

	F1		   141	   	  151
	F2		   142	   	  152
	F3		   143       	  153
	F4		   144       	  154
	F5		   145       	  155
	F6		   146       	  156
	F7		   147       	  157
	F8		   148       	  158
	F9		   149       	  159
	F10		   150		  160
.end literal
.page
.literal




		                  APPENDIX IV


                                USEFUL ROUTINES

.end literal
