PDMS Software Customisation Guide
PDMS Software Customisation Guide
PDMS Software Customisation Guide
www.cadfamily.com EMail:[email protected]
The document is for study only,if tort to your rights,please inform us,we will delete
PLEASE NOTE:
AVEVA Solutions has a policy of continuing product development: therefore, the
information contained in this document may be subject to change without notice.
AVEVA SOLUTIONS MAKES NO WARRANTY OF ANY KIND WITH REGARD TO
THIS DOCUMENT, INCLUDING BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
While every effort has been made to verify the accuracy of this document, AVEVA
Solutions shall not be liable for errors contained herein or direct, indirect, special,
incidental or consequential damages in connection with the furnishing, performance or
use of this material.
This manual provides documentation relating to products to which you may not have
access and which may not be licensed to you. For further information on which Products
are licensed to you please refer to your licence conditions.
All rights reserved. No part of this document may be reproduced, stored in a retrieval
system or transmitted, in any form or by any means, electronic, mechanical,
photocopying, recording or otherwise, without prior written permission of AVEVA
Solutions.
The software programs described in this document are confidential information and
proprietary products of AVEVA Solutions or its licensors.
For details of AVEVA's worldwide sales and support offices, see our website at
http://www.aveva.com.
www.cadfamily.com EMail:[email protected]
AVEVA Solutions Ltd, High Cross, Madingley Road, Cambridge, CB3 0HB, UK
The document is for study only,if tort to your rights,please inform us,we will delete
This page has intentionally been left blank
www.cadfamily.com EMail:[email protected]
The document is for study only,if tort to your rights,please inform us,we will delete
Revision History
Contents......................................................................................................................i
1 Introduction ....................................................................................................1-1
1.1 Customising a Graphical User Interface...................................................................... 1-1
1.2 A Serious Warning About Software Customisation ..................................................... 1-2
1.3 Using the PML 1 Expressions Package in PDMS ....................................................... 1-2
1.4 How to Use this Manual .............................................................................................. 1-2
1.4.1 Hints on the Trying the Examples .............................................................................. 1-3
1.5 Minimising Problems for Future Upgrades .................................................................. 1-4
1.6 Note for Users Familiar with OO Concepts ................................................................. 1-5
2 Variables, Objects, Functions and Methods................................................2-1
2.1 PML Variables ............................................................................................................. 2-1
2.2 Object Types ............................................................................................................... 2-1
2.3 Members and Attributes .............................................................................................. 2-2
2.4 User-defined Object Types.......................................................................................... 2-2
2.4.1 Storing Object Type Definitions.................................................................................. 2-3
2.5 Creating Variables (Objects) ....................................................................................... 2-3
2.5.1 Local and Global Variable Names.............................................................................. 2-3
2.5.2 Notes on Naming Conventions .................................................................................. 2-4
2.5.3 Creating a Variable with a Built-in Type ..................................................................... 2-4
2.5.4 Creating Other Types of Variable............................................................................... 2-5
2.5.5 Using the Member Values of an Object ..................................................................... 2-5
2.6 PML Functions and Methods....................................................................................... 2-5
2.6.1 Storing and Loading PML Functions .......................................................................... 2-7
2.6.2 PML Procedures......................................................................................................... 2-7
2.7 Arguments of type ANY ............................................................................................... 2-9
2.8 Using the Methods of an Object ................................................................................ 2-10
2.8.1 Example.................................................................................................................... 2-10
2.9 Methods on User-Defined Object Types ................................................................... 2-11
2.9.1 Method Overloading ................................................................................................. 2-12
2.9.2 Constructor Methods with Arguments ...................................................................... 2-12
2.9.3 Overloading with ANY .............................................................................................. 2-13
2.9.4 Invoking a Method from Another Method ................................................................. 2-13
2.9.5 Developing a PML Object with Methods .................................................................. 2-13
2.10 The Unset Variable Representations ........................................................................ 2-13
2.11 UNSET Values and UNDEFINED Variables ............................................................. 2-14
2.12 Deleting PML Variables............................................................................................. 2-14
2.13 Forms as Global Variables ........................................................................................ 2-15
3 General Features of PML.............................................................................3-17
3.1 Functions, Macros and Object Definitions ................................................................. 3-17
3.1.1 Comments in PML Files ........................................................................................... 3-17
3.1.2 Leaving a PML File with the RETURN Command ................................................... 3-18
3.2 Case Independence .................................................................................................. 3-18
3.3 Abbreviations............................................................................................................. 3-18
21 Alert Objects.................................................................................................21-1
21.1.1 Position of Alerts ...................................................................................................... 21-2
21.1.2 Input Alerts ............................................................................................................... 21-2
22 The FMSYS Object and its Methods...........................................................22-1
22.1 Querying Forms & Menus System Information.......................................................... 22-1
22.2 Swapping Applications .............................................................................................. 22-2
22.3 Interrupt Methods ...................................................................................................... 22-2
22.4 Refreshing View Gadgets.......................................................................................... 22-3
22.5 Checking References to Other Forms ....................................................................... 22-3
22.6 The Splash Screen.................................................................................................... 22-3
22.7 Default Form Positioning ........................................................................................... 22-3
22.8 The CurrentDocument() Method ............................................................................... 22-3
22.9 The LoadForm() Method ........................................................................................... 22-4
23 PML Add-ins .................................................................................................23-1
23.1 Application Switching ................................................................................................ 23-2
23.1.1 Main form ................................................................................................................. 23-2
23.1.2 Callbacks .................................................................................................................. 23-2
23.1.3 Defining an add-in .................................................................................................... 23-3
23.1.4 Add-in object ............................................................................................................ 23-4
23.1.5 Initialisation............................................................................................................... 23-4
23.2 Menus........................................................................................................................ 23-5
23.2.1 APPMENU object ..................................................................................................... 23-5
23.2.2 Addition of menu items............................................................................................. 23-5
23.2.3 Removing Menu Items ............................................................................................. 23-6
23.2.4 Modifying the Bar Menu ........................................................................................... 23-7
23.3 Toolbars .................................................................................................................... 23-7
23.3.1 Toolbar Control......................................................................................................... 23-8
23.3.2 Removing gadgets from a toolbar ............................................................................ 23-9
23.3.3 Deactivating gadgets on a toolbar............................................................................ 23-9
23.4 Forms ........................................................................................................................ 23-9
23.4.1 Registering a form .................................................................................................... 23-9
23.4.2 Hiding Forms when Exiting Applications ................................................................ 23-10
23.4.3 Storing Data Between Sessions............................................................................. 23-10
23.5 Converting existing user-defined applications ......................................................... 23-11
23.5.1 Replacement of the DBAR file ............................................................................... 23-11
23.5.2 Menu name clashes ............................................................................................... 23-12
23.5.3 Converting the DBAR file ....................................................................................... 23-12
23.6 Example application ................................................................................................ 23-13
23.6.1 Adding a menu field................................................................................................ 23-13
23.6.2 Creating a custom delete callback ......................................................................... 23-13
24 Deprecated, Removed, and Changed Features.........................................24-1
24.1 Notices of Removal ................................................................................................... 24-2
24.1.1 Option Gadget Field Reselection Technique ........................................................... 24-2
24.1.2 Single Choice List field Reselection Technique ....................................................... 24-2
24.1.3 Save and Restore Using .bin files ............................................................................ 24-3
24.1.4 RADIO Gadget ......................................................................................................... 24-4
24.1.5 FMSYS Gadget ........................................................................................................ 24-4
24.2 Notices of Replacement ............................................................................................ 24-4
24.2.1 Deprecated Features................................................................................................ 24-4
24.3 Non Upwards-Compatible Changes at PDMS 11.6.SP1 Release............................. 24-5
This manual describes how to use PML, the AVEVA Programmable Macro
Language. You should use it together with the VANTAGE Plant Design
Software Customisation Reference Manual.
You do not have to be a professional programmer to start to learn PML,
although you may find this manual difficult to follow unless you have some
understanding of programming concepts such as if statements and do loops. If
you have no programming experience, you should consider attending a PML
Training Course. For details, contact your local support office, whose address
is given on the copyright page of this manual.
The current version of PML, sometimes referred to as PML2, may simply be
seen as an extension to the original PML1 facilities. However, the more
powerful techniques that are available mean that many programming tasks
are carried out in different ways.
There are some tasks which are carried out more efficiently using PML 1
facilities. These are described in this manual where necessary. If you are
maintaining old code, you will need to refer to previous versions of this
manual.
The last one to describe PML 1 fully was dated October 1995. The PML1
Expressions system in documented in Appendix C of the VANTAGE Plant
Design Software Customisation Reference Manual.
Most AVEVA products make use of a Graphical User Interface (GUI) to drive
the software. The interfaces provided with your AVEVA software are
designed to apply to a wide range of situations and business needs. However,
as you become more experienced with AVEVA products you may wish to
design an interface that is more closely related to your requirements.
PML 2 has been specifically designed for writing and customising the Forms
and Menus for AVEVA products. Almost all the facilities available in PML 1
and the older Forms and Menus facilities continue to function as before even
if they are not documented here.
Before you begin customising a GUI, you must have a good working
knowledge of the command syntax for the AVEVA product you are working
with. The commands are described in detail in the reference manuals for the
products.
The original expressions package, in PML 1, is still used for writing Rules,
defining Collections and setting Selection Criteria.
For example, this type of expression is still needed for defining Report
templates.
Online help is available in PDMS for the old expressions package.
http://support.aveva.com/support/United_Kingdom/index.htm
When future versions are released, the product documentation will identify
which macro files and which parts of the directory hierarchy have been
modified. You must then decide on one of three courses of action for dealing
with any customised macros which you may have been using:
Warning You should never modify the original files, so that you can
always revert to using these if things go wrong.
Variables are used to store values. Variables have names. The value that is
stored can be changed but the name is fixed. You choose the names and
decide what is stored by each variable.
The variables used in PML 2 are objects:
Every PML2 variable has an object type which is set when the variable is
created and remains fixed as long as the variable exists.
Attempting to store a value of the wrong type in an existing variable will
cause an error. The object type must exist before you can create a variable of
that type.
PML 2 is supplied with built-in object types, system-defined object types, and
you can also define your own user-defined object types.
The built-in object types include the following:
Object Description
Object Description
BOOLEAN This is used for the result of logical expressions and holds
the value TRUE or FALSE
(Note these are not the same as the STRING values ‘TRUE’
and ‘FALSE’).
ARRAY This holds many values of any type and is described in
Chapter 6.
There are also system-defined variable types, such as POSITION and ORIENTATION
in PDMS.
User-defined variable types are explained in Section 2.4.
An object can contain one or more items of data referred to as its members or
attributes. Each member has a name.
You may find that the object types supplied with PML 2 are enough.
However, you can define new object types if you need to. In any case, the
following example may help you understand objects, their members and how
they are used.
The following commands define an object type FACTORY with two REAL
members and a STRING member:
Here is another example where the object type FACTORY is itself used for one of
the data members of another object type:
It is a good idea to use upper case for object-type names, and mixed upper
and lower case for variable names, the objects themselves. For example, a
type might be WORKERS, and a variable name might be NumberOfWorkers
Note that there is no limit to the number of objects you can create of each
type.
Global variables last for a whole session (or until you delete them). A local
variable can be used only from within one PML Function or macro.
!SurfaceArea
!!Area
PML Variable names may be any combination of letters and digits, starting
with a letter, up to a maximum of 16 characters (plus the ‘!!’ or ‘!’). Names are
allowed to contain a dot (.) but this is now strongly discouraged as a dot has a
special meaning in PML2 as a separator between an object and its methods
(see Section 2.8), and between the components of form and gadget names.
Rather than using a dot as part of a name we recommend that you use a
mixture of upper and lower case to make variable names more meaningful,
for example:
!!StartInUpperCase
• Use each variable for one purpose only and give it a meaningful
name.
• Limit your use of global variables.
• Where possible use PML Functions rather than macros (macros are
described in Chapter 7) so as to make use of function return values
and output arguments to return results.
!MyNumber = 99
Because the variable is set to a real, PML knows that its type is real.
Similarly, you can create a STRING variable and set it like this:
The PML Variable !MyString and the constant ‘Hello World’ are both objects of
type STRING. A STRING is a very simple object and the only data it contains is its
text value. In this simple expression we are creating a new object, a variable
of STRING type, by making a copy of the original object, the STRING constant ‘Hello
World’.
Other examples:
!!Answer = REAL()
!Name = STRING()
!Grid = BOOLEAN()
!Lengths = ARRAY()
The dot notation is used in a similar way to access the value of a member of
an object:
!People = !NewPlant.Workers
Functions and Methods may optionally have arguments that can be used to
return values.
Arguments have a data type which is specified in the function or method
definition and they are checked when the Function or Method is called. An
argument may be one of the built-in types REAL, STRING or BOOLEAN; an ARRAY; a
built-in object or a user-defined object or specified as ANY.
Functions and methods can optionally return values as their results.
Functions that do not return values are known as PML Procedures (see
Section 2.6.2).
Here is a definition of a PML Function that has two REAL arguments. It also
has a REAL return value, as shown by the final is REAL:
Inside a function, the arguments are referenced just as if they were local PML
Variables. The RETURN keyword is used to specify the variable that stores the
return value:
When a PML Function is called, all the PML Variables passed as arguments
must already exist.
In addition, arguments used for input must have a value, which could be a
constant, when the function is called:
Here ' FRED ' is a string constant passed as an argument. We could rewrite
this function so that it returns its results by changing its arguments. The
output argument, !Length, will be set to the value required when the function
is called:
Arguments used for output must exist prior to the call and one that is also
used as an input argument must also have a value:
When an argument value is changed within a PML Function its value outside
the function is also changed.
The following call is incorrect, as the function cannot modify a constant:
!PartLength = 7
!PartWidth = 6
!SurfaceArea = !!Area(!PartLength, !PartWidth)
Here we are using an output argument, !Result, to return the result rather
than using a function return value.
The arguments to the !!Area procedure can be set as follows, and then the
procedure invoked with the call command.
!SurfaceArea = REAL()
!Partlength = 7
!PartWidth = 6
call !!Area(!PartLength, !PartWidth, !SurfaceArea)
There will be an error if you attempt to assign the result of a PML Procedure
because there is no return value to assign. So, for example you can say:
Note: As well as procedures, you can invoke a PML Function that has
a return value using call, in which case the function result value
is discarded.
You may specify ANY as the type of an argument (and even as the type of the
function return value).
Note: The use of ANY should be the exception rather than the rule as it
switches off argument type checking - an important feature of
PML Functions to help ensure correct functioning of your PML.
In the case an argument of type ANY, a value of any type may be passed as the
argument to the function:
Where an argument of type ANY is used, you may need to find out its actual
type before you can do anything with it. The ObjectType() method can be used
for this purpose:
2.8.1 Example
This section explains how to use methods, using a STRING variable as an
example. Although the STRING is a simple object type, it has a large number of
methods which can be called.
For example, if you are interested in the length of the string value, look under
the list in the VANTAGE Plant Design Software Customisation Reference
Manual for STRING objects, and you will find a method named Length.
This method returns a REAL value (the number of characters in the string),
but has no effect on the variable itself.
You can extract the number of characters in the string and store it in a new
variable, !Nchars, by calling the method as follows:
Notice the dot separator between the name of the variable and the name of
the method. Also note the ( ) brackets following the name of the method. The
brackets are used to enclose the arguments of the method, but they must be
present even if there are no arguments.
When you define a new object type, you can also define methods which can be
used to handle all objects created with the new type. PML Method definitions
are stored in the same file as the object definition, after the endobject
command.
Here is an example of an object which defines three methods to illustrate the
main ideas. Note that within a method, !This represents the object which
invoked the method and !This.Answer is the way to refer to member Answer of
this object.
Warning: When you create a new object type, or change an existing definition,
you must load the definition by giving the command:
pml reload object _name_
!Marvin.Answer(65)
!Number = !Marvin.Answer()
Then:
!SomeObject.SetValue(100)
!SomeObject.SetValue(‘Priceless’ )
It is not necessary to use this command if you are simply editing an existing
method (although you will have to use it if you edit a form definition file, and
change the default constructor method, described in Section 13.4.)
Each new data type supports a String() method that returns a string
representing the value of the variable. For example:
!X = 2.5 $* defines a variable X of type REAL with 2.5 as its numeric value
!S = !X.String() $* will be a variable of type STRING, with the value “2.5”
User-defined data types can also provide a String() method. These also support
an UNSET representation, and usually adopt the UNSET representation ‘Unset’.
All data types can have the value UNSET which indicates that a variable
does not have a value. A variable created without giving it an initial value in
fact has the value UNSET:
!X = REAL()
Variables with an UNSET value can be passed around and assigned, but use of
an UNSET value where a valid item of data is required will always result in a
PML error.
The presence of an UNSET value may be tested either with functions or
methods:
Functions Methods
if ( Unset(!X) ) then if ( !X.Unset() ) then
if ( Set(!X) ) then if ( !X.Set() ) then
An UNDEFINED variable is one that does not exist. The existence of a variable
may be tested with these functions:
if ( Undefined(!!Y) ) then . . .
if ( Defined(!!Y) ) then
There is no equivalent method call. If the variable does not exist, attempting
to call a method would result in an error.
A variable that exists can be explicitly made UNDEFINED with the Delete()
method:
!!Y.Delete()
In PML 2, forms are a type of global variable. This means that a form cannot
have the same name as any other global variable or any other form.
Note that a form definition is also the definition of an object, so a form cannot
have the same name as any other object type.
Functions and Macros are PML Files that contain stored sequences of
commands. The PML File is invoked whenever this sequence of commands is
required.
The PML File may also include control logic which alters the order in which
the commands are carried out and special commands for handling errors.
PML Files are normally created using a text editor.
PML Functions and methods on objects (including forms) are the
recommended way of storing command sequences because:
• There is a check that they have been called with the right type of
arguments.
• Arguments can return values.
• A PML Function or method can return a result of any type.
Most new AppWare code is written as methods on objects. PML Macros are
explained in Chapter 7 as they are the basis of the older AppWare code.
PML Macros are normally stored in a directory under the PDMSUI search-path.
PML Functions are automatically loaded from a directory under the PMLLIB
search-path.
You can also use $* to add an inline comment to any line of PML:
A comment may extend over several lines provided it is enclosed in the escape
sequences $( and $) .
$( A comment containing
more than one line $)
$(
skip if (!X EQ !Y)
$)
if ( count EQ 0 ) then
return
endif
For clarity, return can be used as the final line of a PML Macro. However, the
use of this command is not essential and there will be no error if it is not
used.
Note that this is a different use of return from the command used to set return
values of variables.
Everything written in PML, including keywords such as if, do and else means
the same thing in upper or lower case.
The exception is text enclosed between quotes or vertical bars, which is used
exactly as it is typed. Throughout this document you will see examples of
PML code using a mixture of upper and lower case for readability.
3.3 Abbreviations
$$
As the last character on a line, $ means that the next line is a continuation
line.
For example:
pml rehash
This command scans all the files under the first directory in your PMLLIB path,
and updates the pml.index file.
If other users have added PML Files and updated the appropriate pml.index
files, you can access the new files by giving the command:
pml index
This command re-reads all the pml.index files in your search path without
rebuilding them.
When you are not running an AVEVA product, you can update the pml.index
file in a given directory by giving the command:
pmlscan directory_name
Note: The commands pml rehash and pml index are a type of command
known as PML directives: they are used outside PML Files to
direct PML itself to take certain actions.
More information about using PML directives with form
definitions is given in Section 13.6.
The following command scans all the files in all the directories in your PMLLIB
path, and updates the pml.index files.
For example:
2+3
is an expression, where 2 and 3 are the operands, and + is the operator. The
result of this expression is 5.
Expressions can (and normally do) contain variables and, in PDMS,
expressions will often contain names of PDMS element types, attributes and
pseudo-attributes.
Expressions can also contain arithmetic and trigonometric functions, such as
the SIN trigonometric function.
Often, expressions will contain logical operators:
!height GT !width
Here the logical operator GT is being be used to test if !height is greater than
!width.
Each expression has a type such as REAL, STRING or BOOLEAN. All the elements
in an expression must be of the correct type. For example:
is meaningless if !X is REAL and will result in an error. (But see Section 4.4 for
using the concatenation operator to convert different types to STRING.)
!X + !Y
In general, you do not need spaces before or after brackets, except when a
PDMS name is followed by a bracket. If there is no space, the bracket will be
read as part of the name. For example:
(Name EQ /VESS1 )
Operators are evaluated in the order of the following list: the ones at the top
of the list are evaluated first.
Operator Comments
Operator Comments
Note: The operators EQ, NE, LT, GT, LE and GE are sometimes referred to
as comparator or relational operators; NOT, AND, and OR are
sometimes referred to as Boolean operators.
See also Section C.11, Precisions of Comparisons for tolerances
in comparing numbers
The & operator concatenates two STRING values (joins them end-to-end) to
make a result of type STRING. Values of any type are automatically converted
to a STRING first:
( (SIN(!angleA) * 2) / SIN(!angleB) )
!SavedValue = !Number
Users familiar with PML1 should note the absence of $ preceding the variable
name. These new expressions do not need to be enclosed in ( ) parentheses:
!NewValue = !OldValue + 1
PML 2 expressions:
Note: Avoid using $ in new PML code as far as possible. There is still a
role for sparing use of $ as it is a flexible and powerful
mechanism - but it should now be the exception rather than the
rule.
!Variable = !!MyFunction()
NEW $!Variable
There are four types of construct for implementing control logic within a PML
Function or Macro. These are:
• The if construct for conditional execution of commands.
• The do command for looping and the associated break and skip.
• The golabel for jumping to a line with a label.
• The handle construct for dealing with errors.
5.1 IF Construct
Once a block of commands has been executed, everything else up to the endif is
ignored.
The else command is optional. If it is included, you can be sure that exactly
one command block within the if-construct will be executed.
The elseif commands are also optional. Once one of the elseif expressions has
been found to be TRUE, any remaining elseif commands are ignored.
Thus the simplest form of the if-construct is:
if ( !Number LT 0 ) then
!Negative = TRUE
endif
You may not concatenate the commands into one line, so the following are not
allowed:
if ( !TrueValue OR !UnsetValue)
if ( !FalseValue AND !UnsetValue)
ignore !UnsetValue if the value is not required to determine the outcome of the
expression. The same is true for PML Functions which have returned an
error.
if ( !Number LT 0 ) then
!Negative = TRUE
if (!Number EQ -1 ) then
!OnlyJustNegative = TRUE
endif
endif
if ( !NewValue - 1 GT 0 ) then
!Success = !NewValue GT 0
if ( !Success ) then
if ( !!MyFunction() ) then
Note that the BOOLEAN constants TRUE, FALSE, YES and NO and their single-letter
abbreviations not enclosed in quotes return BOOLEAN results and so can be
used directly in expressions. For example:
if ( Y ) BOOLEAN
The following do not return BOOLEAN values and are therefore invalid:
For upward compatibility with PML1, STRING variables set to ‘TRUE’, ‘FALSE’,
‘YES’ or ‘NO’ or their single-letter abbreviations can be used in an if-test as long
as they are evaluated with a preceding $. For example:
!MyString = ‘TRUE’
if ( !MyString.Boolean() ) then . . .
Code Result
REAL zero FALSE
$* All other positive and negative REAL values TRUE
STRING ‘FALSE, ‘F’, ‘NO’ and ‘N’ FALSE
STRING ‘false, ‘f’, ‘no’ and ‘n’ FALSE
STRING ‘TRUE’, ‘T’, ‘YES’ AND ‘Y’ TRUE
STRING ‘true’, ‘t’, ‘yes’ and ‘y’ TRUE
5.2 DO Loops
do !x from 10 to 100 by 10
!Total = !Total + !X
enddo
The !X , from, to and by are optional, therefore in its simplest form you may use:
do
commands block
enddo
This will loop forever unless something in the commands block stops the loop
(see break and golabel below)
The elements of the loop are as follows:
Element Purpose
do !Number
if (!Number GT 100) then
break
endif
!Result = !Result + !Number
enddo
do !Number
break if (!Number GT 100)
!Result = !Result + !Number
enddo
Any expression may be used with the breakif command, even a PML Function,
provided the result is BOOLEAN (i.e. TRUE or FALSE).
The ( ) parentheses are optional but recommended.
The loop counter variable retains the value it had when the break from the
loop occurred.
do !X
!Number = !Sample[!X]
if (( INT(!Number / 2 ) NE ( !Number / 2 )) then
skip
endif
!Result = !Result + !Number
enddo
do !X
!Number = !Sample[!X]
skip if ( INT( !Number / 2 ) NE ( !Number / 2 ) )
!Result = !Result + !Number
enddo
do !X to 10
do !Y
!Z = !X + !Y
break if (!Y GT 5)
enddo
enddo
The inner-most loop goes through all the values of !Y before the outer loop
moves on to the second value of !X. Note that the break (or skip) command acts
just on the loop containing it - in this case the inner-most loop.
The golabel command in PML allow you to jump to a line with a matching label
name
LABEL /FRED
:
:
GOLABEL /FRED
The label name /FRED has a maximum length of 16 characters, excluding the /
slash which must be present. The next line to be executed will be the line
following LABEL /FRED, which could be before or after the GOLABEL command.
If the expression !C GT 100 is TRUE there will be a jump to LABEL /FINISHED and
PML execution will continue with the line
$P Total is $!Total
If the expression is FALSE, PML execution will continue with the line:
!Total = !Total + !C
An ARRAY variable can contain many values, each of which is called an array
element. An Array is created automatically by creating one of its array
elements.
!NewArray[1] = !NewValue
This will create an array variable named !NewArray if it does not already exist
and will set element 1 of that array to the value of !NewValue. If !NewArray
already exists as a simple variable, you will get an error message and the
command will be ignored.
Note how array elements are referred to by means of a subscript expression
in [ ] square brackets and that there must be no space between the end of the
array name and the subscript. Array elements are accessed in the same way
when using the value in an expression:
!X = ARRAY()
The array subscript may be any expression which evaluates to a number. One
of the simplest expressions is the value of a variable:
!MyArray[!Next] = 15
!Surname = 1
!Forname = 2
!Employee[1][!Surname] = 'Smith'
!Employee[1][!Forname] = 'Samuel'
!Employee[2][!Surname] = 'Bull'
!Employee[2][!Forname] = 'John'
!FullName = !Employee[1][!Forname] & ' ' & !Employee[1][!Surname]
!TempName[!Surname] = 'Truman'
!TempName[!Forname] = 'Harry'
!Employee[3] = !TempName
!FullName = !Employee[3][!Forname] & ' ' & !Employee[3][!Surname]
!Nelements = !MyArray.Size()
This method sets !Nelements to the number of elements currently in the array.
This is an example of a no-effect method which does not alter the array but
returns a REAL result which can be assigned to another variable.
!MyArray.Clear()
This is an example of a method which modifies the array by deleting all the
array elements but produces no-result value, so there is nothing to assign to
another variable.
There is a third kind of method which both changes the array and returns a
result value. Here the result is assigned to a variable:
!NewArray = !OldArray.RemoveFrom(5,10)
!OldArray.RemoveFrom(5,10)
!Result.Append(!NewValue)
!Result = ARRAY()
If !Result exists already as a simple variable, you will get an error and the
command is ignored.
!MyArray[N].Delete()
The deleted array element would test as UNDEFINED. Note that the array
continues to exist even when you have deleted all its elements.
!ArrayOfFields.AppendArray(!Line.Split())
!LIST[1] 'One'
!LIST[2] 'Two'
!LIST[3] 'Three'
The command:
!Width = !List.width()
would set to !Width to the value 5, the length of the longest element in !LIST,
which is ‘Three'.
Note that if the array contained elements that were not strings, these are
ignored when calculating the maximum width.
!MyArray.Sort()
This is a no-result method that modifies the array by performing a sort in-
situ.
The sort is into ascending order and will be an ASCII sort on an array of
STRING elements and a NUMERIC sort on an array of REAL values.
The Sort() method returns the array itself as a list result, so it is possible to
follow the call to the Sort() method immediately with a call to the Invert()
method, which will return a descending sort:
!MyArray.Sort().Invert()
!NewPositions = !MyArray.SortedIndices()
The array can be sorted by applying the new index values using the ReIndex()
method:
!MyArray.ReIndex(!NewPositions)
More important, the index values in !NewPositions can be used to sort other
arrays as well.
To use some simple examples, imagine we had the array !Animals that
contained:
Index Animal
[1] Wombat
[2] Kangaroo
[3] Gnu
[4] Aardvark
[5] Antelope
The command:
!Animals.Sort ()
Would move the array elements so that they now appeared in the following
order:
Index Animal
[1] Aardvark
[2] Antelope
[3] Gnu
[4] Kangaroo
[5] Wombat
!Index = !Animals.SortedIndices()
Would create a new array !index representing the subscript values of the
array elements in !Animals then sort these index values (without altering the
array !Animals). After the sort, !index would look like this:
Index Subscript
[1] 4
[2] 5
[3] 3
[4] 2
[5] 1
The command:
!Index.Invert()
Index Subscript
[1] 1
[2] 2
[3] 3
[4] 5
[5] 4
If you want to sort the arrays by car model, then on colour, and then on year,
you would give the command:
The sorted index values are put into the array !Index, (for clarity shown here
with the rows of the original arrays they are pointing to),
By default values are sorted ascending order using the ASCII character-
codes. Other options which may be supplied after each array name are:
You can also modify the array to eliminate empty or repeated elements:
Option Effect
To sort these arrays and identify the last occurrence of each group of the
same car type, use the LASTINGROUP option:
This would create !Index by sorting the values in the array !Car , but would also
would also create the array !Last:
[1] 1 1 ⇒ CHARIOT
[2] 2 ⇒ FORD
[3] 4 ⇒ FORD
[4] 5 ⇒ FORD
[5] 10 2 ⇒ FORD
[6] 3 3 ⇒ VAUXHALL
[7] 7 4 ⇒ ford
[8] 9 5 ⇒ vauxhall
[9] 6 ⇒ (Unset)
[10] 8 6 ⇒ (Unset)
Suppose we had sorted the array !Car and another array !Value using the
command:
VAR !Index SORT !Car !Value LASTINGROUP !Group
We can then generate an array of subtotals for each type of car with the
following command:
We then wish to create a new array containing just the employees’ names.
!Names = ARRAY()
do !Person VALUES !MyEmployees
!Names.Append(!Person.Name)
enddo
Each time round the do-loop, the do-variable becomes an object of the
appropriate type, even if the array is a heterogeneous mixture of objects.
Note that the command is enclosed in quotes. The special variable Evalindex is
automatically incremented during the evaluation of the block to the index of
each array element in turn. Finally we use the Evaluate() method to invoke
block processing on the array:
!Names = !MyEmployees.Evaluate(!ExtractName)
Alternatively, you may use an evaluation expression which does not return a
result provided you invoke the evaluation directly without trying to assign
the result. For example, if you have defined a !!Print() function the following is
valid:
On exit from a do values loop PML destroys the loop counter variable.
With do indices the counter takes the value of each array subscript at which an
array element is stored:
!Pump[1] = ’Fred’
!Pump[20] = ’Tom’
!Pump[10] = ’Jim’
do !IN indices !Pump
!Value = !Pump[!IN]
$P Array Element $!N is $!Value
enddo
7 Macros
$M filename
where filename is the pathname of the macro file. The filename may optionally
be preceded by a slash (/) character.
If you give only the name of the file, the program will look for it in the
directory from which you executed the program.
An error message will be output if the file cannot be found and opened for
reading.
$n
will run the macro and will set the lengths defined as $1, $2, $3 to 5000, 200
and 300 respectively.
Arguments may be either values or text, but note that a space in a text string
will be interpreted as a separator between two different arguments.
Apostrophes in text arguments are treated as parts of the arguments, not as
separators between them. For example, if a demonstration macro arg.mac
includes the lines
$P First Argument is $1
$P Second Argument is $2
$P Third Argument is $3
$,
instead of a space.
If you do this, you must end the argument list with the escape code
$.
Note: The full stop is part of the escape code, not punctuation.
$Dn = default_string
For example, if the macro demo.mac expects three arguments, the following
calls to run the macro all omit one of the arguments:
Note: To gain the full benefits of using PML Functions it is best not to
mix Macros and Functions extensively. Many of the advantages
of PML Functions depend on using variables without $ which is
not possible with arguments to macros.
You may use synonyms in macros, although you can not use them in PML
Functions.
This restriction was introduced because changing a synonym (which is global
to the whole program) can cause an unintentional change in behaviour of
individual macros.
There is also a large performance penalty on every line of PML executed
where synonyms are permitted.
Most of this manual describes how to use PML 2 to create and customise
Forms and Menus. This chapter describes how to use PML within AVEVA
products. Note that for tasks such as defining Rules and Report Templates,
you are restricted to the PML 1 expressions package described in the
VANTAGE Plant Design Software Customisation Reference Manual, and it is
also sometimes necessary to use the VAR command.
Index Value
COMPOSE always returns an array with at least one element. The number of
array elements depends on the length of the text strings supplied and the
width of each column. Notice that all of the STRING array elements are space-
padded to the same length.
Keyword Effect
Keyword Effect
The following are used to pass the name of a variable into PDMS as part of a
stored expression so that the value is taken when PDMS processes the stored
expression rather than PML extracting the value at the time the line is read:
VVALUE( !X )
VTEXT( !AString )
VLOGICAL( !Aboolean)
!Item = !!CE
!!CE is of type DBREF so the new variable !Item will also be of type DBREF. The dot
notation can be used to access attributes and pseudo-attributes of a database
element:
!Bore = !Item.bore
This form of access can also be used directly on the !!CE variable:
!Owner = !!CE.owner
!Rating = !!CE.cref.pspec.rating
Assigning a new reference to the !!CE variable makes the new reference the
current element by navigating to it in the database:
!!CE = !!CE.owner
P-points are accessed using the P-point number like an array subscript. For
example, to access the direction of P-point[1]:
There is also the PDMS function BADREF which will detect whether a database
reference is unset or invalid (i.e. impossible to navigate to):
You can still assign an attribute value in this way even if the PML DBREF is
not the current element':
!A = !!CE
!!CE = !!CE.Owner
!A.Built = TRUE
You can even assign a PML object, such as POSITION, where this corresponds to
the type of the attribute:
Note that where the type of an attribute is a PML object, it is not possible to
set an object member value, such as the up value of a POSITION, directly – this
must be done in two stages:
!Pos = !!CE.Position
!Pos.Up = 2000
!!CE.Position = !Pos
Current Session
Sessions
Projects
Teams
Users
MDBs
DBs
These commands can be used as in the following example. The SESSION object
has a method that returns name of the MDB in the current session. Hence:
!C = current session
!CurrentMDB = !C.MDB()
8.3.4 Collections
You can create an array which includes a number of elements which all
satisfy specific selection criteria, as defined by yourself. This is a useful way
of collecting information on particular elements. You use the syntax:
!Array is the name of the array that will be created to contain the elements
selected.
The following general criteria can be used to define the selection:
For example:
Command Effect
The command:
Would create the array !PIPECOMPS and set it to contain the reference numbers
of every piping component in the MDB.
Logical expressions, which return TRUE or FALSE, can be used. They are most
likely to be used to check the value of an attribute for collection. The WITH or
WHERE options introduce the expression. For example:
would collect all elements for which the attributes XLEN, YLEN and ZLEN match
the criteria in the array !LENGTHS.
A volume is defined by the WITHIN keyword. You can define the volume either
in terms of two diagonally opposite points of an enclosing box, or as a volume
around an element (with an optional clearance around the box which contains
the element). For example:
collects all elements in the defined volume into the array !VOLUME.
collects all piping components within the volume defined by a box ‘drawn’
1500 mm around /PUMP1 and puts them into the array !P. The EXCLUSIVE
keyword indicates that only the chosen elements exclusively within the given
volume are to be selected.
Hierarchy criteria can be defined by the FOR keyword. It identifies a list of
elements below which all selected elements must occur. You can also include
an exclusion list. For example:
You can append the results of such a collection to an existing array using the
APPEND keyword. For example:
Would add the references for all elbows to the array !BENDS.
You can also overwrite elements in the array by specifying the first index in
the array which you want to be overwritten. The specified index, and the
indexes following it, will be overwritten by the results. For example:
Would place the reference for the first ELBOW selected at position 99 in the
array !BENDS, overwriting any existing data, and subsequent selections in the
array elements that follow.
Where:
You can append the results of such an evaluation to an existing array using
the APPEND keyword. For example:
will add the values calculated from the expression for all BOXES to the (already
existing) array BOXES.
You can also overwrite elements in the array by specifying the first index in
the array which you want to be overwritten. The specified index, and the
indexes following it, will be overwritten by the results of the evaluation. For
example:
will place the result of the first evaluation for the selected elements at index
99, overwriting any existing item, and the following results in the subsequent
array elements.
where … represents any of the standard VAR syntax for setting variables.
There are several ways PDMS adds entries to the undo system:
undoable to the undo stack. Make your database changes, and then
call the method endUndoable().
• Automatically whenever a model element is moved using graphical
interaction techniques in Model Editor.
Every time you select an undo operation an entry is taken off the undo stack.
The state saved in this undoable is restored, and the undoable object is placed
on the redo stack.
When the undo stack is empty, then the Undo button and the Undo menu
option will be greyed out indicating that there are no operations remaining
that can be undone.
If the operation of undo involves moving into or out of model editing mode,
then the switch into that mode will happen automatically, and the model
editor button and menu option will reflect the change.
The selection set and handle appropriate to the editing operation that was
being used will also be restored.
There are also a number of ways that you can perform an undo:
Assignment using = , the assignment operator, usually does what you would
expect, but a detailed explanation of how the different data types are handled
may be helpful.
9.1 Assignment
!X = !Y
If, for example, !Y is an array, this command will duplicate the entire array
making a copy of each of the array elements. The same is true if !Y is an
OBJECT.
The technical term for this is deep copy. Following this copy
!!Form and !!Form.Gadget are both PML references. After the command:
!X = !!Form.Gadget
!X is now a new reference, but the gadget itself has not been copied. Both PML
Variables now refer to the same gadget.
will both have the same effect and will assign a new value original gadget.
You can think of a reference as another name for the same object or variable.
9.3 DB References
!X = !!CE
!X is now a new reference to the same DB element, but the element itself has
not been copied.
!Value = !X.Attribute
!X = !Y
will make a deep copy of !Y. However, if any of the array elements is a
reference (e.g. to a gadget or DB element), a copy is made of the reference, but
not of the object it refers to. In other words a deep copy stops copying when it
reached a reference.
The values printed for !Argument and !!GlobalVar will both be 'NewValue'.
!S = ‘Old Value’
!!ChangeString ( !S )
However, the following will result in a PML error message because the value
passed to the function as an argument is a CONSTANT STRING value which
cannot be modified.
PDMS Database Attribute are read only, and so they cannot be given new
values by assigning to them.
The 46 is the module or program section which identified the error and is the
error code itself is 28.
If the input line had been typed interactively that is the end of the story.
However, if the input line was part of a PML Macro or function the error may
optionally be handled.
An error arising during the processing of a PML Macro or function does not
immediately give rise to an error message - this depends on the next line of
input.
Provided the next command processed by PML is a matching handle
command, the error is not output and the commands within the matching
handleblock are processed instead.
elsehandle blocks may optionally also be present — if the handle block does not
match the error one elsehandle will be processed — if it matches the error:
If (46,27) matches the error, PML processes the commands in that handle block
instead of outputting an error. Processing of the current PML Macro or
function continues at the line after the endhandle command.
Note the keywords ANY and NONE which can optionally be used in place of a
specific error code.
If the line following a line which has caused an error is not a handle
command, the outcome depends on the current setting of onerror (see next
section). The default setting is onerror RETURN and the current macro or
function is abandoned.
However, if in the calling PML Macro or function the next command to be
processed is a handle command, it now gets an opportunity of handling the
error (and so on up the calling PML).
onerror RETURN
which causes the current macro or function to be abandoned and gives the
calling macro or function an opportunity to handle the error.
Another possibility is to jump to one section of code in the same macro or
function after any unhandled error:
To suppress errors, and error alerts the following may be used, for example
during non-interactive testing:
onerror CONTINUE
Although the effect of errors is suppressed, any error messages generated will
still be output. Beware of using this option which can have unpredictable
effects. The option is applied to all subsequently nested PML Macro and
function calls.
When debugging, you may interrupt normal PML processing after an error:
onerror PAUSE
The effect is the same as $M- and will allow you to type commands while the
PML File is suspended. You must type $M+ to resume the PML processing.
Do not leave this in working code.
After handling an error, you can still output the detail of the error message
with the following commands:
$P $!!Error.Text
$P $!!Error.Command
$P $!!Error.Line
do !line VALUES !!Error.Callstack
$P $!Line
enddo
To abandon the running PML Macro or function, but to re-instate the error so
that the calling PML code has a chance to handle it, you can use the
command:
return error
You can also re-instate the error but suppress the alert using the command:
To generate a new error (or replace an error with your own error) plus an
optional message, use one of the following
return error 1
return error 1 ‘Your error message’
return error 1 NOALERT
handle 1
PML code to handle a user-defined error number
endhandle
Reading and writing files is greatly simplified by using the FILE object. This
chapter describes the methods most frequently used for reading and writing.
Methods are also provided for moving, copying and deleting files and
extracting information such as the pathname of a file, its size data and time
last modified.
A FILE object may refer to a directory rather than a file and methods are
provided for navigating around the directory structure.
For a complete list of the methods available, refer to the VANTAGE Plant
Design Software Customisation Reference Manual.
A file object is created by invoking the FILE constructor with the name of the
file as its argument. For example:
At this stage, the file may or may not exist — creating the FILE object does not
open or access the file in any way.
11.1.1 Example
This example reads pairs of numbers from file data, adds them together and
writes the answers to file RESULTS.
When reading a file one line at a time using the ReadRecord() method you must
open the file first with the Open(‘READ’) method and close it afterwards with the
Close() method. Each line read from the file will be returned as a STRING until
the end of the file is reached, when you will get an UNSET STRING returned.
The UNSET string can be detected using the STRING object's Set() method (or
Unset()) as in the example above (See Section 11.1.1).
When you open a file for writing, the file will be created if it does not already
exist.
If you use Open(‘WRITE’) and the file already exists, the user will be shown an
alert asking whether the file can be overwritten. Alternatively you may
specify OVERWRITE, to force overwriting of a file if it already exists or APPEND if
you want to add to the end of a file if it already exists.
You will obtain much quicker performance if you read or write an entire
array in a single operation. In particular you are recommended to use the
ReadFile() method which returns the whole file as an array of strings, opening
and closing the file automatically:
Note that with the ReadFile() method you may optionally specify the maximum
number of lines you are prepared to read and an error is raised if this number
is exceeded. If not specified, a limit of 10000 is imposed.
Fully developed PML code should - if required to - interact with the user by
means of forms, menus, and alert boxes. However, while you are still
developing your PML code the facilities described here might be useful.
The commands described here should normally only be typed interactively or
included in a PML File on a temporary basis. None of these commands should
remain in fully developed PML code.
If a PML File does not appear to be running in the way you expect the easiest
thing to do is to turn on PML Tracing with the command:
PML TRACE ON
With PML Tracing switched on, each of the PML lines executed is output to
the parent window together with its line number. Additional tracing
messages tell you when you have begun to process a new PML File and when
it has finished. To turn off tracing type:
These commands can also be put into a PML File on a temporary basis.
You can also turn PML tracing on by setting the Environment Variable
PMLTRACE to ON before you start the program.
For more precise control of PML tracing you can use the $R command. $R100 is
the equivalent of PML TRACE ON and $R0 is the same as PML TRACE OFF.
Type the command $HR for online help on how to use the $R command.
It is often useful to output a line to the screen from within a running PML
File to indicate that the execution of the program has reached a particular
stage. Use the $P command:
The alpha-log does not include standard PML tracing from the command PML
TRACE ON. For PML tracing to be included in the alpha-log, PML tracing
should be directed to the alpha-window. For example, to obtain standard
PML tracing in the alpha-log use the command:
$R102
If you cannot find out what is going wrong by means of PML trace output or
writing out the values of PML Variables, you may suspend a running PML
File at a particular point by including the command:
$M-
You can then query the values of any PML Variables of interest and even
change the values of some PML Variables. To resume processing of the
suspended PML File type into the command line:
$M+
Use these facilities only for debugging and do not leave these commands in a
finished PML File.
$QM
Command Effect
$Q
This will produce a list of every valid command word or argument type that
you may enter next.
The list may be long and could include every valid command for the module
that you are in.
The $Q facility is also useful to establish what is allowed as the next
component of a command. Type the beginning of the command sequence
followed by $Q.
13.1 Overview
As a user of AVEVA products, you will already be familiar with forms, and
the gadgets (buttons, textboxes, etc) on them.
In PML 2, forms are a type of object represented by a global variable — the
form’s name, for example !!EntryForm. This means that a form cannot have the
same name as any other object type, global variable, or any other form.
The form object owns a set of predefined member variables and built-in
methods. In addition, you can define your own members — form variables
and form gadgets — and your own form methods. All these will determine the
content and functionality of the form.
Gadget objects are user-defined members of the form object. Form members
are always accessed using the dot notation, for example
!!EntryForm.TextField
!!EntryForm.TextField.val.
Note: All the in-built members and methods of forms and gadget-types
are listed in the VANTAGE Plant Design Software
Customisation Reference Manual.
Callbacks are user-defined actions assigned to a form and its gadgets and
that are executed when the operator interacts with the form, for example, by
clicking a mouse button on a gadget.
The callbacks are supplied as text strings and may be any valid PML
expression, PML Function or method call, including any form, gadget or user
defined object method. Effectively, these callbacks determine the intelligence
of the form.
The following are examples of the format of form and member names:
Note that total length of the name is limited to 256 characters even though
the length each individual components is limited to 64 characters. Within the
form definition, the members of the form should be referred to by using !This
to replace the form name part of the gadget name. For example:
!This.GadgetName
!This.GadgetName.val
exit
Some points to note about the above definition and the form it creates are:
To display the form in this example, you can use the command:
show !!Hello
!this.message.val = ‘Modified’
will set the value member of the gadget Message on this form to read Modified
rather than Hello world.
|!!OtherForm.Para.val = ‘Modified’|
Form definitions must be held one per file. The file name must be the form’s
name in lowercase with the file extension .pmlfrm. For example, our form !!Hello
would be captured in a file called hello.pmlfrm. This definition file should be
stored in a directory pointed to by the PMLLIB environment variable. It will
then be loaded automatically on execution of the show !!Hello command.
The form definition file contains:
• The form definition between setup form and exit. This includes the
commands which create the form itself, and set its attributes, such
as its size and title, the commands which create the gadgets on the
form and specify how they are arranged, and the definitions of any
variables which are to be members of the form.
• Any method definitions should follow the exit command, each
method beginning with the define method command and ending with
endmethod. Methods on forms are just like methods on any other kind
of object – see Section 2.9
• In particular, it will contain the form's default constructor method.
This is a method with the same name as the form, and no
arguments. It is the only method called automatically when the
form is loaded, and so it can be used, among other things, to set
default values for the gadgets on the form.
• The form may be given an initialisation method, which is run
whenever the form is shown (as opposed to when it is loaded). See
Section 15.3.2.
• No executable statements should appear in the file outside of the
form definition or form methods. The effect of misplaced executable
statements is indeterminate. You can put comments anywhere in
the file.
A form definition must be loaded before the form can be displayed. If you
have stored the definition in a .pmlfrm file then loading will be automatic when
the form is displayed for the first time. Normally, a form is displayed as a
show !!formname
Sometimes it is useful to force the loading of a form’s definition file before the
form is actually displayed, so that you can edit the form or gadget attributes
from another form’s callbacks before the form is actually displayed. Using
the command
loadform !!formname
from a callback will force load the definition if the form is unknown to PML,
but do nothing if the form has already been loaded.
Once a form has been displayed you can remove it from the screen using the
command
hide !!formname
Note that if you show it again it will appear on the screen, but its definition is
already known to PML and so it will not be loaded.
kill !!formname
The form is then no longer known to PML until a new definition is loaded.
Note: Earlier AppWare used form definitions in macro files which had
to be loaded explicitly via $M path-name-to-file. This mechanism still
operates for backwards compatibility, but is strongly
discouraged when writing new AppWare.
You will need to use PML directives when you are developing new form
definitions or modifying existing ones. PML directives are commands of the
form pml . . .
The table below gives some useful PML directives.
Command Effect
Command Effect
See Chapter 12 for tracing commands that will be useful when you start to
develop PML code.
Our simple form !!Hello, which we constructed earlier in this chapter, is not
very intelligent. Once we have pressed the Change button the .Message
paragraph will read ‘Modified’ for ever more, even if we hide the form and re-
show it.
The extended version of form !!Hello below:
First save the definition in a file called hello.pmlfrm and ensure that its
directory is in your PMLLIB search-path.
PML rehash
show !!Hello
This will auto-load the form definition and execute the default constructor
method (which will set the message paragraph to ‘Hello world’ and define the
gadget and form callbacks). It will also display the form.
Type your message into the Enter message field and press the Enter key. This
will execute the field’s callback, which will write your typed text into the
message paragraph.
Type a new message and press Enter. The paragraph updates to reflect what
you typed.
Click the Goodbye button. This executes the form’s Okcall action which calls
the success() method. The success() method sets the paragraph to ‘Hello again’ and
blanks out the text field. Finally, the OK control action hides the form.
Show the form again and observe that the paragraph reads ‘Hello again’ and not
‘Hello world’. This demonstrates that when you re-show the form the form’s
constructor is not run, because the form is already loaded.
If you want to reset the form every time it is shown, you must define a form
initialisation callback — see Section 15.3.2.
Note: This chapter looks at the callback in more detail. If you are
reading this manual for the first time then you may want to skip
this chapter and return to it later.
Before you read this chapter you should have read and understood the Form
Concepts chapter, in which we saw that callbacks are user-defined actions
which are assigned to a form and its gadgets
They are supplied as text strings and may be any valid PML expression, PML
Function or method call, including any form, gadget or user-defined object
method.
‘$m %pathname%/MyMacro’
‘q var !!form’
‘q var !!form.gadget’
which will write out details of the form or gadget and its members. You might
like to try it on the form !!Hello.
Typical expressions for a callback are
‘!this.gadget.val = !MyObject.count’
‘!MyObject.count = !this.gadget.val’
which get or set the value of a gadget on the form from or to a user-defined
object.
Note: Before you read this section, make sure that you understand
user-defined methods, as described in Section 2.9.
The .success() method above could only deliver a fixed string ‘Hello again’ to the
message PARAGRAPH gadget. The great advantage of methods is that you can
pass variables as arguments to the method, so it can be used more generally,
for example as the callback to several gadgets.
When the OK button is pressed the Okcall action will invoke the success()
method, passing to it the message paragraph gadget as !output, the message text
‘Hello again’ as !message and the text input field gadget capture as !input. The
method will do just what it did before.
When clicked, the Restart button‘s callback will execute and set the message
paragraph gadget to read ‘Hello world’ and clear the capture text field, thus
restoring the form to its state when it was displayed for the very first time.
If we invoked the success() method as:
it would set the value ‘Hello world’ into the capture text input field and clear the
contents of the message PARAGRAPH gadget. Not what you need here perhaps,
but you can see how versatile methods can be!
Note: The arguments to methods can be any valid PML object types,
built in or user defined.
14.3.1 Events
When the operator interacts with a GUI, an event occurs. For example, when
the operator:
'!this.MethodName('
Note the open bracket '(', no arguments and no closing bracket. The callback
is to an open method or function.
We might assign an open callback to a multi-choice list gadget as follows:
When a list field is clicked, the list’s callback will be examined and if it is an
open method or function, then the Forms and Menus software will supply the
arguments required to complete the function.
Thus in this case the actual callback string executed will be
Inside the control() method we branch on the value of !action and access the data
of !object (in this case our list). Finally we perform our application’s resultant
action - in this case just printing out all we know about the operator
interaction using the $p command, which for a selection of an un-highlighted
list field will write:
Notice that the same method could be used to manage several or even all
gadgets on our form since the variable !object is a reference to a gadget object
and is supplied as !!Open.choose, the full name of the gadget including its form.
This allows us to find everything about that object from its in-built methods,
including its gadget type (LIST, TOGGLE, etc) and its owning form:
!type = !object.type()
!form = !object.owner()
All the in-built members and methods of forms and gadget types are listed in
the VANTAGE Plant Design Software Customisation Reference Manual.
Note that the function has a global name !!control, that is, it is not a member of
any form or object and thus cannot use the !this variable.
The open callback on the choose list gadget would become
AVEVA developers can define PML forms, menus, and gadgets that can be
core-code controlled. See Appendix A.
Before reading this section you should have read the Form Concepts chapter.
The Main form has a menu bar that provides access to all the functionality of
the current application of the module, from its pull-down menus (the main
menu system), and a set of tool bars, each containing gadgets (usually icon
buttons, icon toggles and pull-down lists) designed to give fast access to
frequently used functions.
The Main form is not displayed directly, but supplies all its menus and tool
bars to be displayed in the Application Window.
• The AppWin Menu Bar, which contains the Main form’s menu bar.
• The Dialog Bar, which contains the Main form’s tool bars.
• The Document Area, which contains one or more document forms,
which are normally constrained to this area.
• The Status Bar, which displays current status, messages and
general information to the user.
The picture below shows a typical example of what the AppWin looks like:
For more detailed information about forms in the context of a Vantage PDMS
application, for example, how to define an AppWindow and a main
application form and swap to it, see Chapter Error! Reference source not
found..
The structure of a form definition file has already been discussed in Section
13.4. The form definition is a command sequence starting with:
exit
• The commands which create the form itself and set its attributes,
such as its minimum size and title.
• The commands which create the gadgets on the form, and specify
how they are arranged.
• The definitions of any variables which are to be members of the
form.
• Form type.
• Minimum size.
• Resizability.
• Docking.
• Form position
• NOQUIT
• NOALIGN
Here are some examples of ways you can set up forms of different types:
setup form !!myform dialog dock left Creates a resizable docking dialog;
setup form !!myform dialog resizable Creates a resizable floating dialog;
setup form !!myform dialog Creates a non-resizable floating
dialog;
setup form !!myform Creates a non-resizable floating
dialog;
setup form !!myform document Creates a resizable MDI child
document;
The RESIZABLE command means that the form will be displayed with re-sizing
controls at its corners. This will allow the user to change the size of the form.
Docking forms and all document forms are resizable by default; but for other
types, if you do not include the RESIZABLE command, the size of the form is
fixed.
If you have a View gadget on the form it will resize itself with the form by
moving its bottom right hand corner to maximum extent of the form.
You can modify the title at any time using the FormTitle member:
The icontitle sub-command is used to supply a string that is used when a form
is iconised. To set the icon title:
You can also modify the icon title at any time using the IconTitle member:
You can set the callback by assigning to the form’s initcall member. This can be
done with the INITCALL command:
INITCALL ‘!This.InitCallBack()’
or directly by
!!MyForm.initcall = ‘This.InitCallBack()’
If the callback discovers an error so serious that the form cannot be displayed
it can abort the display of the form by returning an error. You can supply the
text of an error message that is to be presented in an error alert in place of
the form:
If the initialisation callback has already caused an alert to be raised then you
can prevent the raising of a new error alert by using the NOALERT keyword:
OKCALL ‘CallbackString’
!this.Okcall = ‘CallbackString’
Families) or when the window’s CLOSE gadget is used. It allows the operator
not to proceed with the functions of the form.
The form is then removed from the screen and all gadgets are automatically
reset to the values they had when the form was displayed or when any APPLY
button was last pressed. Typically this callback allows you, the PML
programmer, to undo any actions already carried out on the form that ought
to be undone in the light of the CANCEL request
You can assign to the form’s CANCELCALL member using the command
CANCELCALL ‘CallbackString’
!this.Cancelcall = ‘CallbackString’
For forms of type MAIN, the QUITCALL callback is executed, if present. This
permits the user to terminate the application, and so the associated PML
callback should prompt the user for confirmation.
If the user confirms the quit, then the callback should close down the
application, and not return. If the user decides not to quit, then the callback
should return an error to indicate the decision to F&M.
Use return error…noalert if you want to avoid displaying an error alert. If the
form has no QUIT callback, then the QUIT event will be ignored.
The following example shows a (global) PML function, that you could be use
from all forms of type MAIN:
This would be called from the form definition function body or from its
constructor method as shown below:
For all other form types, the QUIT callback is executed, if present, and then the
form and its children are hidden unless the PML callback returns an error.
When the form nest is hidden the CANCELCALL callback for each form of the
nest is executed (in reverse display order).
Note F&M does not display an alert for the returned error, it is merely for
communication.
You don’t need a QUIT callback if you just want to allow the form to
be hidden.
For DOCUMENT forms (MDI children) only, the callback must not
display an alert as this will cause some gadgets to malfunction
afterwards.
Form members are defined in just the same way as object members:
The value of a form member can be set and used in just the same way as an
object member:
!!MyForm.MyNumber = 42
!Text = !This.MyNumber
!ThirdValue = !This.MyArray[3]
!ThirdValue = !This.MyArray[3]
q var !!formname
This will list all the attributes of the form, and all the gadgets defined on it.
This is a useful debugging aid.
To query all the gadgets of a form (excludes USERDATA gadget) use:
!!gadgetsarray = !!MyForm.gadgets()
The Form Family exists just as long as the forms are displayed. If a form is
already on the screen when it is shown, it is brought to the front of the
display. If the child form is already in a Form Family it is transferred to the
new parent.
If the user presses the OK button of a parent form, the system in effect
presses the OK buttons on each of the child forms, 'youngest' first, invoking
their OKCALL callbacks. The parent form and all child-forms are hidden and
the Form Family then ceases to exist.
If the user presses the CANCEL button or uses the window's CLOSE controls,
the system in effect presses the CANCEL buttons of each of the child forms,
'youngest' first, invoking their CANCELALL callbacks, and all the forms in the
Form Family are hidden.
The action of RESET and APPLY buttons does not affect family members.
Note: Earlier AppWare used form definitions in macro files which had
to be loaded explicitly via $m path-name. This mechanism still
operates for backwards compatibility, but is strongly
discouraged when writing new AppWare.
show !!formname
used in the gadget’s callback. In either case the form becomes a child of the
menu’s or gadget’s owning form.
A form may be displayed free-standing, i.e. not as a child, by:
Sometimes it is useful to force the loading of a form’s definition file before the
form is actually displayed, so that you can edit the form or gadget attributes
from another form’s callbacks before the form is actually displayed. Using the
command:
loadform !!formname
from a callback will force load the definition if the form is unknown to PML,
but do nothing if the form has already been loaded.
If you are sure that a form’s definition has been loaded then you can show the
form as a child or free-standing respectively using the form methods:
!!formname.show( )
!!formname.show( ‘free’ )
but note that this will not dynamically load the form definition.
The At option puts the origin of the form at the specified position;
alternatively the Cen option puts the centre of the form at the given position.
The co-ordinate values are fractions of the screen width or height respectively
and are referred to as screen co-ordinates.
For example:
positions the origin of !!MyForm one quarter of the way across from the left edge
of the screen, and one tenth of the way down from the top.
Forms may also be cancelled by using the window’s close controls. Both these
mechanisms will remove the form and any of its children executing their OK
or CANCEL callbacks appropriately.
Sometimes it is required to hide a form and other forms which are
functionally associated but not part of the form family or as a result of a
button press on a form you may want to hide other associated forms but not
the form whose button was pressed. The hide command or method allows this:
hide !!MyForm
!!MyForm.hide()
Note that when you explicitly hide a form in this way its gadgets will be reset
to their values at display or at the last APPLY, just like a CANCEL action, but the
CANCELCALL callbacks for the form and its nest will not be applied. This means
that before you execute the hide you should use any pertinent data from the
forms to be hidden.
kill !!MyForm
The form is hidden and then its definition is destroyed so that it is then no
longer known to PML. You cannot then access the form or its gadgets,
members or methods (including its .show() method.
Normally you will not need to include the kill command within your
AppWare.
If you re-show the form using the show command then the system will attempt
to demand load the definition again. This is slow and expensive if you haven’t
modified the definition so avoid it: use loadform !!MyForm and !!MyForm.show()
instead.
If you execute a setup form !!MyForm... while the form !!MyForm already exists then
it is killed and a new definition is started. This mechanism may be useful
because it makes it possible to generate a form definition interactively from
within your AppWare.
This can be very powerful but should be used with great care.
By default, you can quit from any user-defined form, except for the current
system Main form.
You can save the current state of a running module to a set of files from
which you can restore the state again at a later time.
15.5.1 Save
The command
saves the current state of the module to the specified file with a .bin suffix.
You can optionally choose to overwrite an existing file.
There may also be module-specific options that support the saving of the
contents of graphical views to a correspondingly named display file that has a
.disp suffix. For example:
15.5.2 Restore
The command
• Destroys the entire current user interface (deletes all forms, menus
and their data structures)
• Reinstates a new user interface from the binary file - this replaces
the set of CP synonyms with the set present when the binary file
was created.
• Restores the PML Variable store state that was present when the
binary file was made
!formref = !!MyForm
!gadgetref = !formref.MyGadget
INSTALL /savefile.bin
!gadgetref.val = "new value" -- gadgetref may not exist or may be a
-- different-- gadget or a form etc
!formref.hide() -- formref may not exist or could be a different form
When the callback is executed the current GUI, including the form or gadget
which owned the callback, is destroyed and replaced by a new GUI from the
binary file. References to previous forms or gadgets may now inadvertently
point to different forms or gadgets (because they are pointers directly to the
GUI data structures) and using them may produce unexpected results, eg
hiding the wrong form or even causing a crash.
Note that remaking the references after the Install will correct the problem
(as long as the new GUI has a !!MyForm which actually represents the same
form as it did before:
!formref = !!MyForm
!gadgetref = !formref.MyGadget
INSTALL /savefile.bin
!formref = !!MyForm -- may produce an error if !!MyForm does not
-- exist in the installed GUI.
!gadgetref = !formref.MyGadget -- may produce an error if MyGadget does
not exist on the new GUI's !!MyForm
!gadgetref.val = "new value" -- will now work if MyGadget is same type
-- of gadget in the new GUI
!formref.hide()
Core managed forms are shown and hidden by core-code actions and cannot
be ‘killed’ by PML AppWare. See Appendix A.1, PDMS Form core support
Menus are always members of forms but can be employed in various ways by
the form and its gadgets.
Menus come in two types: main menus and popup menus. You determine
what type a menu is when you create it. If you do not specify the type, then
the system will try to infer its type from the context of its first use.
For example, if the first action in a form definition is to define the menubar,
then the system will infer any menus referenced in the bar…exit sequence to be
of type MAIN.
Or, as a second example, if a menu is assigned as the popup for the form or a
gadget of the form, then the system will infer the menu to be of type POPUP.
Forms may have a bar menu gadget or main menu, which appears as a row of
options across the top of the form. When you select one of the menu options, a
pull-down menu is temporarily displayed. Fields on a menu may have pull-
right arrows (>) that open a pull-down sub-menu when selected.
Forms and gadgets can have popup menus assigned to them. When you move
the cursor onto them and press the mouse popup button, the menu pops-up at
the cursor and you can then select from the displayed options.
The following rules determine how you can use menus:
• Each menu belongs either to the Main menu system or to the Popup
menu system, but cannot belong to both.
• A menu in the Main system can appear only once. i.e. it cannot be a
sub-menu of several menus.
• A menu in the Popup system may appear only once in a given popup
tree, but may be used in any number of popup trees.
• A menu cannot reference itself, either directly as a pullright of one
of its own fields or be a pullright of another menu in its own menu
tree.
• Any pullright field of a menu references a sub-menu that will be
inferred to be of the same type as the referencing menu.
A bar menu is defined within a form definition. The menu bar is created with
the bar subcommand. Note that its name is ‘bar’: there can be only one bar
menu on a form. Then you can use the bar’s Add() method to add the options.
For example:
This code specifies the text of three options labelled Choose, Window, and
Help.
• The Choose option when picked will open the menu Menu1 as a pull-
down (assuming you have defined Menu1).
Note: Note that Menu1 need not exist when the bar is defined, it
can be defined later in the form definition, but it must
exist before the Choose option is selected or an error alert
will be raised.
• The Window and Help options will open the Window and Help
system menus (described later in this chapter).
• Execute a callback.
• Display a form.
• Display a sub-menu.
This creates a new main menu menu with six fields and two separators
between them. For example:
• The SAVE field when picked will execute the callback command
this.SaveFile().
• The Save as... field when picked will load and display the form
!!SaveFile. By convention, the text on a menu field leading to a form
ends with three dots, which you must include with the text
displayed for the field.
• The SEPARATOR, usually a line, will appear after the previous field.
• The Pull-right1 field when picked will display the sub-menu !this.Pull1
to its right. A menu field leading to a sub-menu ends with a >
symbol: this is added automatically.
You can add menu fields with an optional fieldname that you can later refer
to when editing the menufield or modifying its attributes’. If you do not
specify a field name then you will not be able to refer to the field again. You
can also assign a name to separator fields, which allows separator group
editing.
Note: Before Version 11.6, menu fields could only be referred to via
their display text. This made internationalising the AppWare
very difficult because all references to the display text have to be
found and modified. Using named fields removes the problem
because the display text occurs only in the menu definition.
Field Description
This menu is dynamically created on use with a list of the titles of the
windows currently displayed as its fields. Selecting a field will pop that
window to the front. This can be very useful on a cluttered screen.
When selected, this Help option displays a system-help pull-down menu that
gives access to the application help system. The fields are:
Field Description
Contents This displays the Help window so that you can find
the required topic from the hierarchical contents
list.
Index This displays the Help window with the Index tab
selected, so that you can browse for the topic you
want to read about from the alphabetically-
arranged list. You can locate topics quickly by
typing in the first few letters of their title.
Search This displays the Help window with the Search tab
at the front so that you can find all topics
containing the keywords you specify.
About To see the product version information.
You can access On Window help by pressing the F1 key while the form has
keyboard focus, or by including a Help button in the form’s definition.
Note: By convention, the help menu should be the last one defined for
the menu bar, which will ensure that it appears at the right-
hand end of the menu bar.
For example:
!menu.popupGadget() is GADGET
If the menu was a popup on a gadget then the returned GADGET variable is a
reference to the gadget. If the menu was popped up from a pulldown-menu or
from a popup on the form itself, the value is UNSET.
Example:
!g = !menu.popupGadget()
if !g.set() then
!n = !g.name()
$p menu popped up by gadget $!n
else
!n = menu.owner().name()
$p menu popped up by form $!n
endif
For example, in your form definition you can add a toggle field as follows:
Note how we use the PickedFieldName member of the menu object to obtain the
last picked field.
If you pick this menu field the callback method will print:
The contents of menu bars and menus can be modified at any time using the
members and methods of the bar menu gadget object and the menu object.
Field Description
For example:
If you use the identifier ‘Window’ or ‘Help’ as the name of the menu, the system
will interpret them as system Window and Help menus, although they will
still be displayed with the string given in <dtext>.
Named menus and the methods that create them are discussed in more detail
in the rest of this section.
InsertBefore(<TargetFieldName>,<FieldType>,<Dtext>,<Rtext>,{<FieldName>})
InsertBefore(‘SEPARATOR’,{<FieldName>})
InsertAfter(<TargetFieldName>,<FieldType>,<Dtext>,<Rtext>,{<FieldName>})
InsertAfter(‘SEPARATOR’,{<FieldName>})
Field Description
You can de-activate a menufield on a menu bar and a field in a menu with the
SetFieldProperty() so that it cannot be selected. Similarly, you can make them
invisible so the user cannot see them.
You can also use SetFieldProperty() to hide a menufield and to select or unselect
toggle-type fields.
The general syntax is:
Field Description
For example:
!bar = !!MyForm.bar
!menu = !!MyForm.Menu1
sets local variables !bar and !menu to be references to the bar gadget and menu
Menu1 of form !!MyForm.
Then
will grey-out the menufield on bar that has the field-name “Foo”. And
will activate the menufield on Menu1 that has the field-name “Bar”.
You can use the same method to change the selected status of a toggle menu
field.
To read the status of a menu or of a menu-field property, you can use the
FieldProperty() method.
The general syntax is:
Field Description
For example:
!bar = !!MyForm.bar
sets local variable !bar to be a reference to the bar gadget of form !!MyForm.
Then
will get the greyed-out status of the menufield on bar that has the field-name
“Foo”.
You can use the same method to change the selected status of a toggle menu
field.
will make the all the fields invisible for the group currently implied by the
separator field ‘SaveGroup’, i.e. the fields SaveGroup, Save and SaveAs.
The combination of named SEPARATOR fields, insertion and field group
visibility will be useful for managing the sharing of menus between co-
operating sub-applications. This facility should be used with great care.
Typically gadgets are laid out onto the form from left to right and from top to
bottom. It is unnecessary and undesirable to specify absolute positions for
gadgets; we recommend defining the layout of each gadget relative to a
predecessor. This allows the layout to be edited simply, without having to
calculate new positions.
• The origin (0,0) of the grid is at the top left-hand corner of the form.
• The horizontal pitch is the notional character width for the
currently selected font.
• The vertical pitch is the notional line-height, which is the height of
the tallest single line gadget for the currently selected font, i.e. the
maximum height of a textual TOGGLE, BUTTON, OPTION or TEXT gadget.
At any time the form has maximum and minimum extremities XMIN, YMIN,
XMAX, YMAX. As new gadgets are added to it the form XMAX and YMAX extents
grow to include the gadget boxes.
Note: The grid width is the notional character width because fonts
usually have proportional spacing so different characters in the
font typically have different widths. Thus n grid units does not
equate to n characters. Generally, you can get more than n
characters in n grid units unless the string has a high proportion
of wide characters e.g. capitals, numerals, w’s, m’s. It is
important that you understand this concept when you specify
the width and height of gadgets.
We recommend you use NOALIGN in conjunction with PATH RIGHT (the default
path) and HALIGN CENTRE, as it gives a better layout, with fewer surprises.
0 1 2 3 4 5 6 7 8 9 X
0
1 YMIN
2
3
4 YMAX
5
Y XMIN XMAX
It is recommended that you layout a form using one or both of the following
schemes. Both allow the form design to have gadgets added, removed, and
repositioned, without having to adjust the geometry of all other gadgets on
the form.
Auto-placement uses the PATH, DISTANCE and ALIGNMENT keywords. These
keywords have the following meaning:
Keyword Description
PATH is the direction in which the next gadget origin will be
placed relative to the previous gadget.
DISTANCE is the spacing between gadgets along the current path.
ALIGNMENT specifies how the next gadget aligns to the previous one
for the current path.
17.3 Auto-placement
PATH right
PATH left
PATH up
PATH down
HDIST 4
VDIST 2
Note that these specify clearance distances between gadgets (for example, the
distance between the XMAX of one gadget and the XMIN of the next), not the
distance between gadget origins, thus:
.GADG1 .GADG2
HDISTANCE
VDISTANCE
.GADG3
HALIGN left
HALIGN centre
HALIGN right
VALIGN top
VALIGN centre
VALIGN bottom
The following diagram shows the effects of all possible combinations of path
and alignment settings (with a fixed clearance distance, D, in each direction):
PATH last D
next next next
last last
D D
PATH
next last next last next last
D D D
D D D
D D D
.But1
.Par5
Positions the origin of the new toggle gadget with respect to the extremities of
the last-created gadget (indicated by the absence of an explicit gadget name
in the AT command). The new gadget’s origin is at the coordinates (XMIN,
YMAX+1) of the last gadget:
0 1 2 3 4 5 6 7 8 9 X
0
1
2
previously-created gadget used as
3
4 YMAX
5 YMAX+1
6
Y
XMIN new toggle gadget
Figure 17-6:Positioning Relative to Specific Previous Gadgets
Positions the new toggle to the left of .Gadget1 (since the specified X offset is
negative):
0 1 2 3 4 5 6 7 8 9 X
0
1
2
existing gadget used as reference
3
4 YMAX
5 YMAX+1
6
Y
XMIN-2 XMIN new toggle gadget
Figure 17-7: Newly Placed Gadget
Note: The new gadget need not be adjacent to the referenced gadget(s).
The same rules apply even if there are other gadgets positioned
between them. You will probably find form design easier,
however, if you add gadgets in two directions only (right and
down, say), rather than in a more random order.
XMAX FORM and YMAX FORM refer to the maximum X and Y coordinates for the
entire form so far.
XMAX FORM - SIZE subtracts the current gadget’s size so that the form will not
expand. The net result of the above command is to add the OK button so that
in the X-direction it just finishes at the form’s current maximum extent
without increasing the form width, and in the Y-direction the gadget’s origin
is placed at the form’s current maximum depth and extends it to include the
gadget’s height. The result is:
0 1 2 3 4 5 6 7 8 9
0
1 Original YMAX FORM
2
3
BUTTON .OK gadget
4
5
6
7 New YMAX FORM
Figure 17-8: Positioning Relative to Form’s Extremities
Note that each gadget coordinate is independent with respect to auto and
explicit placement. All the following are legal constructs:
places .t1 with respect to XMIN of one gadget and YMAX of a different gadget.
places .t2 with respect to XMAX of the last placed gadget and YMAX of a specific
gadget Gadget2.
PATH down
...
toggle .t3 AT xmin.Gadget1
places .t2 with respect to XMIN of gadget .Gadget2, whilst the Y coordinate for .t2
is auto-placed at current VDIST value below the last placed gadget.
positions a new toggle gadget with its origin at grid coordinates (3, 3.5), thus:
0 1 2 3 4 5 6 7 8 9 X
0
1
2
3
4
5
6
7
Y
Figure 17-9: Positioning at a Known Location
Note: You can position gadgets anywhere on the grid, not only at the
grid intersection points.
The AT syntax is used to define the position of a gadget’s origin within a form.
The position may be specified absolutely (in form layout grid units) or relative
to the extremities of existing gadgets, or relative to the size of the form and
the gadget.
The rest of the Forms and Menus syntax is described in VANTAGE Plant
Design Software Customisation Reference Manual: refer to that manual for
more information, in particular about conventions used in the syntax graphs.
The AT syntax graph is the easiest way of illustrating all the possible options,
and so it is included here, as well as in the VANTAGE Plant Design Software
Customisation Reference Manual.
where <FGREL>, shown below, sets the gadget position relative to another
gadget or the form’s extent. For example, it can be used to position a gadget
half-way across the width of a form:
>----+- <gname> -.
| |
+-- FORM ---|
| |
‘-----------+- * val --.
| |
+- + val --|
| |
+- - val --|
| |
+- val ----+--- + val * SIZE --.
| | |
| +-- - val * SIZE ---|
| | |
| +- - SIZE ---------|
| | |
| `-------------------|
| |
+-- SIZE ----------------------|
| |
`------------------------------‘--->
Syntax Graph 17-2: Placing a Gadget Half-Way across the Form
Below are some examples of how you can use the syntax:
Syntax Effect
AT 5 7.5 Puts gadget origin at form grid
coordinates (5, 7.5).
AT X 5.5 Puts gadget origin at form grid
coordinates (5.5, y) where y is
calculated automatically from the y
extremity of the last placed gadget and
the current VDISTANCE setting.
AT YMAX+1 Positions new gadget at (x, y) where x is
calculated automatically from the x
extremity of the last placed gadget and
the current HDISTANCE setting, and y is
Syntax Effect
at YMAX+1 of the last gadget.
AT XMIN.GAD1-2 YMAX.GAD2+1 Positions new gadget with respect to
two existing gadgets. The gadget is
offset by 2 grid units to the left of
.GAD1(X=XMIN-2) and 1 unit below .GAD2
(Y=YMAX+1).
AT XMAX FORM-SIZE YMAX FORM-SIZE XMAX FORM refers to the current right
hand size of the form at its current
stage of definition (not its final
maximum extent). YMAX FORM refers to
the form’s current bottom extent. The -
SIZE option subtracts the size of the
gadget being positioned in the form.
This example positions the gadget at
the extreme right-hand bottom edge of
the form.
So far we have considered the static layout of the form. But often our forms
need to be resized by the user at run-time.
Most gadgets also have DOCK and ANCHOR attributes that allow you to define
intelligent position and resize behaviour when the gadget’s own container-
gadget resizes.
This allows you to have more than one resizable gadget on the same form and
to have predictable and potentially complex resize behaviour.
The DOCK and ANCHOR attributes are mutually exclusive. Setting the DOCK
attribute resets the ANCHOR to the default; setting the ANCHOR attribute resets
DOCK to none.
You can set these attributes only when you define the gadget: you cannot
change it after the exit from form setup. Thus you are not allowed to change
the resize behaviour at run-time.
At present ALPHA and VIEW gadgets support neither the DOCK nor ANCHOR
attributes. However, as these gadgets expand fully to fit their containers; you
can place them in their own frame, with no other gadgets, and set the frame’s
DOCK or ANCHOR attributes to get the behaviour you desire.
The ANCHOR attribute may have any combination of the values LEFT, RIGHT, TOP,
or BOTTOM; or it may have the values NONE or ALL. When the container is
resized, the fixed distance is maintained for any anchored edges.
Examples of the use of the gadget anchor attribute are shown in Section
20.1.2 Complex Form Layout.
Frames are very special and versatile gadgets that are crucial for form
definition, layout, and run-time behaviour. This section gives an overview of
frame gadgets. Their definition and details are discussed in Section 19,
Gadgets and their Attributes.
There are three different types of frame, and each type has different
constraints on what gadgets it can contain and what it can be used for.
The three types of frame are normal, tabset, and toolbar.
The tabbed page frame may contain any form gadgets including normal frame
gadgets.
To create a multi-paged tabbed form, you can define a dialog or document
form with a single TABSET frame that contains a set of tabbed page frames,
with each page containing the gadgets for the desired page of the form.
The form will automatically resize to take account of the largest tabbed page
frame. There is an example showing the definition of tabbed frames in
Section 20.1.2, Complex Form Layout
You cannot nest TABSET frames.
As a user, you will already be familiar with forms and their gadgets. The
types of gadgets that you can define on the body of the form are summarised
below.
Refer to Figure 20-1 for examples of the following:
Gadget Purpose
Gadget Purpose
You can define gadgets only within the form definition sequence,
setup form… exit.
A gadget definition (except for menu bars) has the format:
For example:
Specific properties: the order of these commands generally matters. See the
syntax graphs in the VANTAGE Plant Design Software Customisation
Reference Manual for definitive information about order.
Most gadget properties can be changed using the members and methods
supported by each gadget object.
Note: You cannot change a gadget’s geometry except for a VIEW gadget
on a resizable form.
• SLIDER, PARAGRAPH, G3D and G2D do not display their tag at all and so
it doesn’t affect the gadget size.
• FRAME and RGROUP gadgets display their tag as an integral part of
their surrounding box, and so the tag contributes to the gadget
width and height.
• LIST, SELECTOR and TEXTPANE gadgets display their tag above the
gadget’s box. It affects the gadget height but not the width.
• OPTION, TEXT, TOGGLE and RADIO_BUTTON gadgets display their tag
horizontally next to the gadget glyph and/or value indication and it
affects the width but not the height.
• BUTTON gadgets display their tag inside the button glyph whose
width and height can now be specified independently of the actual
tag string.
• ALPHA gadgets (not in FRAME gadgets) display their tag above the
bounding box, so it affects the gadget height but not the width.
ALPHA views within FRAMES do not display their tag at all, so it has
no effect on the size.
The Tagwidth specifies the size of the gadget’s tag field in grid width units
including any padding space, regardless of the actual tag string.
The actual tag may have more characters than the declared Tagwidth and still
fit in the tag field (typically a mostly-lower-case string of 10 characters
occupies only about 60-70% of the 10 X notional character spaces). Similarly
the actual strings may have fewer characters than the declared Tagwidth and
the extra space will be blank padded.
Note If the tag width is not explicitly given then it is assumed to be the
number of characters in the ‘tagtext’ string multiplied by the
horizontal grid size (the notional character width for the font).
You can specify the tag width without specifying any tagtext at
definition time; you can add this at run time.
The Tagwidth is not needed for gadgets with an explicit area specification
(width and height, lines or length). FRAME, LIST, SELECTOR, TEXTPANE and
PARAGRAPH can always force an explicit width (excluding any padding).
For example, the following PARAGRAPH gadget definition displays the given
string, which has 14 characters without lots of unused space:
Form layout syntax has been extended to allow a gadget’s width and/or
height to be specified relative to the size of previously placed gadgets:
The frame’s width is set to the width of gadget gad6 and its height is set to
the height of the last (most recently defined) gadget.
The text field gadget text1 reserves 6 grid units for its tag and 20 grid units
for its text display, but the actual gadget length is greater than this because
of padding space in the strings and space for the visible box.
The option gadget option1 also reserves 6 grid units for its tag (though the
tag text has 8 characters, rather than 6) and specifies the text display
(including the drop-down glyph) must be the same width as the text1’s text
display (excluding the tag).
The two gadgets have the same X co-ordinate and their display fields will
align at their start, because they have the same tag width, and at their end
because they have the same length.
The frame gadget’s X co-ordinate is incremented with the desired tag width
and so will also align at its start with option1. The frame’s width is set to be
the same as the width of option1 (excluding the tag) and so aligns with the
end of option1 also.
All the gadgets have their anchor attributes set to allow the form to be
resizable. When the form is interactively resized the gadgets will adjust to
maintain their initial alignments. The frame will expand to take up any spare
space on the form.
Gadgets with TEXT, OPTION WIDTH and HEIGHT define the data
an optional in- TOGGLE RTOGGLE display space in grid units.
line tag. These settings exclude the tag
and any gadget glyph or
decoration.
Boxed gadgets LIST, SELECTOR, TEXTPANE WIDTH defines the width of a
with optional data display line in grid units
tag above. and HEIGHT defines the number
of visible data lines. The box
may include scroll bars to
expose data lines that do not fit
into the display space defined,
and excludes any tag.
Gadgets with Gadgets that never WIDTH and HEIGHT define the
no tag or with display a tag: FRAME, (possibly implicit) enclosing box
an integral SLIDER, G2D, G3D, GM3D, in grid units.
(optional) tag. PARA.
Gadgets with integral WIDTH and HEIGHT define the
(optional) tag: FRAME, implicit enclosing box in grid
BUTTON. units.
ALPHA: a boxed gadget WIDTH defines the width of a
with optional tag above. data display line in grid units
and HEIGHT defines the number
of visible data lines. The box
may include scroll bars to
expose data lines that do not fit
into the display space defined,
and may also include a data
input line with a prompt above.
RGROUP: a boxed gadget Its size is always implicitly
with integral (optional) defined by the number of radio
tag.. buttons included in its
definition
The relative gadget extent settings define the data display part of the gadget
being defined in terms of the data display part of the specified or implied
gadget.
For the three categories defined above, WIDTH.GAD and HEIGHT.GAD have the
following meanings:
• If only one pixmap file is supplied, it will be used for all states.
• If the Selected pixmap is unset, then it reverts to the Unselected
one.
• If the Inactive pixmap is unset then it will be displayed as blank.
Note: The AddPixmap() method can be used only in the form's default
constructor method; that is, they must be defined before the
form is displayed. Pixmaps cannot be dynamically changed once
the form is displayed.
For example:
para .Para pixmap width 320 height 216
One of the following lines would then be added to the form's
default constructor method:
!gadget.AddPixmap( !P1 is STRING )
!gadget.AddPixmap( !P1 is STRING, !P2 is STRING )
!gadget.AddPixmap( !P1 is STRING, !P2 is STRING, !P3 is STRING )
Where:
!P1 is the gadget's unselected pixmap filename
!P2 is the gadget's selected pixmap filename
!P3 is the gadget's inactive pixmap filename
If a parameter is the null string, ' ', then that pixmap is not changed in the
gadget, so for example you can set the unselected and inactive pixmaps only
by using:
Code Effect
!p2 = '/%Mysearchpath%/selected.png'
Code Effect
!!MyForm.List.Active = FALSE
!!MyForm.List.Active = TRUE
!MyForm.setactive( TRUE )
!MyForm.setactive( FALSE )
If you want most of the gadgets on the form to be de-activated, you can de-
activate all gadgets on the form (and then activate the ones you want,
individually) using the following form methods:
SetActive(false) greys out all gadgets on the form, but doesn’t set their Active
status, so that SetActive(true) restores the form to the precise state it was in
before greying-out, that is, any inactive gadgets will still be inactive.
The command:
SetGadgetsActive( false )
Greys-out all gadgets on the form and sets their active status to inactive i.e.
their previous active state is lost. Similarly
SetGadgetsActive( true )
All gadgets have a visibility member attribute that you can access with PML.
For example, to make a gadget invisible:
!!myform.mygadget.visible = false
!bool = !!myform.mygadget.visible
!!form.f1.visible = false
will cause the frame and all its gadgets to be hidden, but the query:
!value = !!form.b1.visible
The keyboard focus defines which gadget will receive keystrokes. The FORM
object has as one of its properties the name of the gadget which will initially
have the keyboard focus. This default keyboard focus can be changed by
setting the keyboardfocus member of the form:
!!MyForm.keyboardfocus = !!Myform.gadget
The keyboard focus can be moved at any time to one of the following types of
gadget by calling the setfocus() method on the target gadget:
• TEXT
• TEXTPANE
• BUTTON
• TOGGLE
• RTOGGLE
• SLIDER
• LIST
• SELECTOR
• RGROUP
• OPTION
• ALPHA VIEW
For example:
!!MyForm.Textfield.Setfocus()
!Gadget.Refresh()
You can also use the command REFRESH to refresh all gadgets of all displayed
forms.
At PDMS 11.6.Sp1 the gadget method Background(), which returns the gadget’s
background colour as a colourname string, has been extended to most gadgets
(BAR excluded).
The following restrictions apply:
This chapter describes all the gadgets supported by PML. It covers their
definition and use.
20.1 Examples
This file layout1.pmlfrm, shown below, defines the form shown in Figure 20-1
Examples of different types of gadgets. Note that all the gadgets on the form
are dummies: there are no callbacks. The PATH commands control the layout:
they are described in Section 17.3.1.
PATH DOWN
frame .frame2 'Frame 2' at XMIN FORM
paragraph .Message2 text 'This frame contains a horizontal group of radio buttons' width 20
lines 2
rgroup .Horizontal 'Alignment' HORIZONTAL
add tag 'Left ' select 'LEFT'
add tag 'Centre ' select 'CENTRE'
add tag 'Right ' select 'RIGHT'
exit
exit
The file layout2.pmlfrm, shown below, defines the form shown in Figure 20-3.
Within the form definition the TABSET frame is defined and directly contains a
frame gadget for each tabbed page. Note its ANCHOR ALL setting which
maintains the distance between each edge of the frame and the corresponding
edge of the form, when the form is resized by the user. This allows the frame
to grow and shrink without overwriting gadgets outside of it.
Each tabbed page frame contains the definition of all the gadgets belonging to
the page. Note the use of the DOCK FILL setting which allows each edge of the
tabbed page frame to stick to the corresponding edge of the TABSET frame so
that they grow and shrink in unison.
Alternatively, as of PDMS 11.6.SP1, when you define a TABSET FRAME, you can
specify its DOCK or ANCHOR attributes to determine its resize behaviour within
your form.
For each tabbed-page frame within the TABSET, it is no longer necessary to
specify any DOCK or ANCHOR attribute settings, and any that are specified will
be ignored. Each tabbed-page frame will always fill the available space in its
TABSET parent (it exhibits DOCK FILL behaviour).
The gadget ANCHOR attribute is used extensively to allow resizable gadgets to
expand in specific directions and not others for. It is also used by non-
resizable gadgets, e.g. BUTTONs, to allow them to move with edges of their
containers and so avoid being overlaid by resizing gadgets.
Note also, the extensive use of form methods to provide the intelligence of the
form as gadget callbacks. In particular the method listCallback(!list is GADGET,
!event is STRING), which just reports details of select and unselect evetns on list
fields, has the standard form of an open callback, and is used as such on the
list gadgets LI1 and LI2, i.e. !this.Li1.callback = |!this.listCallback(|. Open callbacks are
described in Section 14.3.
path DOWN
frame .Tabset TABSET 'tabset' anchor All
frame .page1 |Page 1| dock Fill
path right
button .CANCEL at XMIN form YMAX form anchor L + B CANCEL
button .RESET anchor L + B RESET
exit
--Page 1
-- frame 4
-- option
!ColourArray[1]='Black'
!ColourArray[2]='White'
!ColourArray[3]='Red'
!ColourArray[4]='Green'
!ColourArray[5]='Blue'
!This.Colour.Dtext=!ColourArray
-- set callback - make pragraph the selected colour
!this.colour.callback = |!this.message4.background = !this.colour.selection('dtext')|
-- frame 5
-- multi-choice list
do !i from 1 to 20
!Elements[!i] = 'list element $!i'
enddo
!This.Li1.Dtext= !Elements
-- set callbacks
!this.b1.callback = |!this.printListSelections(!this.li1)|
!this.li1.callback = |!this.listCallback(|
-- frame 6
-- make Area read-only
!this.Area.seteditable( false )
!this.Width.val = 6.0
!this.Height.val = 3.5
!this.b3.callback = '!this.calcArea()'
--Page 2
-- frame 7
-- textpane - add data
!s[1] = 'Try editing the contents of this textpane gadget'
do !i from 2 to 100
!s[!i] = 'textpane line $!i'
enddo
!this.text.val = !s
-- frame 8
-- multi-column list
-- Define headings
!a[1] = 'Make'
!a[2] = 'Model'
!a[3] = ' Price'
!this.li2.setHeadings(!a)
-- set up dtext rows as array of array
!Row1[1] = 'Landrover'
!Row1[2] = 'RangeRover'
!Row1[3] = '£62000'
!Row2[1] = 'Landrover'
!Row2[2] = 'Defender'
!Row2[3] = '£23999'
!Row3[1] = 'Lancia'
!Row3[2] = 'Delta'
!Row3[3] = 'not for sale'
!Row4[1] = 'Fiat'
!Row4[2] = 'Tempra'
!Row4[3] = 'offers'
!Row5[1] = 'VW'
!Row5[2] = 'Golf GTi'
!Row5[3] = 'p.o.a.'
do !i from 1 to 5
!dtext[!i] = !Row$!i
enddo
!this.li2.setRows( !dtext )
-- Add data
do !i from 1 to !dtext.size()
!rtext[!i] = 'row $!i'
enddo
!this.li2.rtext = !rtext
-- set callbacks
!this.b2.callback = |!this.printListSelection(!this.li2)|
!this.li2.callback = |!this.listCallback(|
endmethod
!name = !list.fullname()
$P -----------------------------------------------
$P selected field for list $!name
$P Field $!num: <$!sel>
$P -----------------------------------------------
endmethod
Frame gadgets provide visual grouping of gadgets on a form, and aid form
layout. One gadget, the RTOGGLE, can exist only in a FRAME.
The grouping is more than visual: a frame is a genuine container and owns
the gadgets it contains, so gadgets are positioned relative to the frame’s
origin rather than the form’s origin.
When a container resizes it will adjust the layout of all its children, taking
account of their anchor or dock properties.
The frame gadget’s properties visible and active will automatically apply to all of
its children, but will not overwrite their corresponding property values. So,
for example, frame .f1 contains button .b1 and f1 and b1 both have visible = true.
The command:
!!form.f1.visible = false
will cause the frame and all its contained gadgets to be hidden, but the query:
!value = !!form.b1.visible
All the gadgets defined after the frame command and before exit will be
included in and contained by the frame.
The following command sequence defines Frame 1 and the gadgets it contains:
Frame Size
During form definition, once a frame is positioned on the form the origin
remains fixed but the frame automatically expands downwards and to the
right to contain any gadgets added to it. You cannot add gadgets to it at
negative coordinates relative to the frame’s origin. You can optionally declare
a minimum size for the frame. For example:
This is relevant only for NORMAL and TABSET frames; for TOOLBAR frames, the
gadgets appear as a single row in the order defined i.e. gadget positions are
ignored.
The radio group action only applies to FRAME gadgets of type NORMAL.
You can add RTOGGLE to a FRAME with the usual positioning and layout
commands.
The FRAME has a value member, VAL, which is the index of currently selected
RTOGGLE for the radio group. You can this to change the selected RTOGGLE.
Similarly, you change the value of the FRAME by setting the VAL member of any
of the group’s RTOGGLEs to true.
Note that the FRAME group value may be set to zero, indicating that there is
no selected RTOGGLE. Similarly if the selected RTOGGLE value is set to false,
then it becomes deselected and the FRAME value will then be zero.
The default value for an RTOGGLE gadget is FALSE, and the default value for a
FRAME gadget is zero, i.e. no selected RTOGGLE.
The Frame Radio Group supersedes the RGROUP gadget, and you should use it
in preference.
Frame Callbacks
The FRAME gadget can have an assigned callback, which is executed when the
radio group selection is changed, i.e. whenever the user selects an unselected
radio-toggle. As there is only a SELECT action supported, it can be either a
simple callback or an open callback.
The form definition below is a simple TV and radio station selector, shown
above.
Note that the form’s keyboard focus is initially placed on the OK button to
prevent it being assigned (by Windows) to the first RTOGGLE rad1 (effectively
the first interactive gadget on the form as the text field Selection is read-only)
The form constructor method assigns a simple callback, the form method
RGroupSelectionChanged(), to the frame rg1 (radio group). It then initialises the
gadget values and selects the second RTOGGLE as the default selection.
The group callback uses the FRAME’s VAL member to get the current selected
index and hence the current RTOGGLE and its OnValue member value. If the
selected RTOGGLE’S value is ‘radio’ then the selected program is read from the
RADIO option gadget. Finally the selected program string is displayed in the
Selection (read-only) text gadget.
The callback on the RADIO option gadget, detects if the ‘Radio:’ RTOGGLE rad5 is
current and if so it deselects it leaving no current selection, and clears the
Selection text field.
You do not need to set the value in the setup form sequence: you can leave it
until a value is assigned to its val member, but you must give a textual
paragraph gadget an initial size if you do not give it an initial text value.
For multi-line paragraphs the text is line-wrapped and formatted into the
available space. It can contain explicit newlines to achieve the desired format.
paragraph .picture AT . . .
pixmap /filename
paragraph .picture AT . . .
pixmap /filename width 256 height 200
The pixmap may be changed at any time by assigning a new value to the .val
member:
!!MyForm.picture.val = /newfilename
When the user presses a button gadget (control button) it will usually display
a child form or invoke a call-back - typically a PML Form method.
Buttons have a tag-name or pixmap which is shown within the button
rectangle. The tag, pixmap, call-back, and child form are all optional.
(See Section 19.3 for more about pixmaps).
For example:
You can specify the width of the BUTTON independently of any tag text string it
contains using the WIDTH syntax. You can also define its height with the HEIGHT
syntax, allowing you to define textual BUTTONs taller than a single character
in height.
For example:
Note The BUTTON‘s tag is always centre-aligned within the define area.
For these buttons, the Unselected and Selected pixmaps swap whenever the
button is pressed, so alternating between the two images in the pressed and
un-pressed states.
Textual Buttons
Toggle buttons will highlight when pressed. For example on toolbars they will
turn from blue to orange when pressed, and go back to blue again when un-
pressed.
The syntax to select the new mode is toggle, which can be anywhere after the
button name and before the button control type or associated form, e.g.
Note that this button deliberately does not have a callback. When this button
is pressed, the form nest is removed from the screen and its CANCELCALL
callbacks executed.
TOGGLE gadgets are used for independent on/off settings as opposed to a radio
group. A TOGGLE should be given a tag name or pixmap, which is displayed to
the right of the TOGGLE button.
In Figure 20-1, the three TOGGLES are defined by the following lines.
They are named Bold, Italic and Underline, and they are tagged with
corresponding text, enclosed in quotes.
More examples:
The value of a toggle gadget is set and used via the .val member which is a
BOOLEAN value:
The RTOGGLE gadget is very similar to the TOGGLE gadget, but is allowed only
in FRAMEs, where they operate together to form a set of radio buttons, only one
of which can be selected at any one time.
You can add RTOGGLE gadgets to a FRAME with the usual layout and positioning
commands. The RTOGGLE gadgets are implicitly numbered 1, 2, 3, … n as they
are added.
RToggle Callbacks
Note that the behaviour of the two versions is identical. Both mechanisms are
equally valid, and are provided to minimise the work required in replacing
the RGROUP and (deprecated) RADIO gadgets.
Events for the radio group FRAME and its radio-toggles happen in the following
order, when an RTOGGLE is selected:
UNSELECT on previously selected RTOGGLE (if any)
SELECT on new RTOGGLE
SELECT on FRAME
Note The RGROUP gadget is superseded by the Frame Radio Group, which
you should use in preference.
As of PDMS 11.6.SP1 you can use the setActive methods to control the active
(greyed-in) status of individual radio buttons of the RGROUP gadget:
Where index is the button number within the group and active is the active
status; and
setActive( !rtext is STRING, !active is BOOLEAN )
The tag subcommand specifies the display-text (or Dtext), which is shown
against the button, and the select subcommand specifies the replacement-text
(or Rtext), which is the value associated with that button: see below.
The radio groups on the form shown in Figure 20-1 are defined by the
following lines:
PATH DOWN
...
rgroup .Horizontal 'Alignment' HORIZONTAL
add tag 'Left' select 'LEFT'
add tag 'Centre' select 'CENTRE'
add tag 'Right' select 'RIGHT'
exit
...
rgroup .Vertical 'Alignment'
add tag 'Top' select 'TOP'
add tag 'Middle' select 'MIDDLE'
add tag 'Bottom' select 'BOTTOM'
exit
The layout of the radio gadget is by default controlled by the current PATH
setting. This may be overwritten, for the current radio group only, with the
VERTICAL or HORIZONTAL keyword.
Note the HORIZONTAL keyword used in the example, which is necessary after
the PATH DOWN command, but that no VERTICAL keyword is needed.
The RGROUP gadget also allows you to define the inter-button spacing
explicitly, independently of the auto increment. You specify the spacing in
form-definition grid (char) units, i.e. the same units as HDIST and VDIST. The
default spacing is 0.0 for either horizontal or vertical radio groups.
Note: Previously it was HDIST or VDIST, which defaulted to 1.0 and 0.25
respectively, but the new gadget has greater innate inter-button
spacing, which approximates fairly well to these values.
By default, for a vertical group, the length in characters of the longest tag in
a vertical group determines the width of the group. Similarly by default the
number of characters in each tag of a horizontal group determines the tag’s
width, so you must pad the tag names with spaces so that they are all of the
same length, to space the buttons uniformly.
Alternatively, you can specify the tag width for all of the enclosed radio
buttons using the BUTTONWIDTH keyword.
The BUTTONWIDTH specifies the size of the tag field for each of the enclosed
buttons, independently of their actual tag strings. As for TAGWIDTH the actual
strings may have more or fewer characters than the declared BUTTONWIDTH.
This provides a mechanism to force the RGROUP gadget to any desired size.
add tag 'Bold Text ' select 'BOLD' callback '!!Bold ()'
Note: If you supply a callback for the whole gadget as well as for a
single button, the whole gadget callback is invoked and not the
callback on the button.
The SELECT keyword in the add command for each button defines its
replacement-text string (Rtext).
When you query the current selection using the gadget's selection() method, it
will return the RText of the currently selected button as a STRING:
!!MyForm.Style.select('ITALIC')
The .val member of the RGROUP refers to the currently selected button number
within the group.
For example:
!!MyForm.Style.val = 2
if ( !!MyForm.Style.Val EQ 1 ) then
An OPTION gadget offers a single choice from a list of items. (See also Section
20.10.1) The items in the list can be either pixmaps or text strings, but not a
mixture. The gadget displays the current choice in the list.
When the user presses the option gadget, the entire set of items is shown as a
drop-down list and the user can then select a new item by clicking the option
required.
There is always a selected value unless the option list is empty.
At PDMS 11.6.SP1 you can use the new Add methods to add a single new
entry to be appended to OPTION gadgets:
Where Dtext is the text to be displayed in the option list, and Rtext is the
replacement text for the new field.
If Rtext is not specified, it will be set to the Dtext string by default.
!ColourArray[1]='Black'
!ColourArray[2]='White'
!ColourArray[3]='Red'
!ColourArray[4]='Green'
!ColourArray[5]='Blue'
!This.Layout2.Colour.Dtext=!ColourArray
Other examples:
!CircleDtextsArray[1] = '/directory/circle/cenrad'
!CircleDtextsArray[2] = '/directory/circle/3pts'
!!MyForm.Circle.Dtext = !CircleArray
option .Circle1 AT . . . callback '!!MyFunc()' PIXMAP width 256 height 128
option .Circle2 AT . . . callback '!!MyFunc()' PIXMAP width 256 aspect 2.0
!!Layout2.Colour.select('Dtext','Orange')
!!MyForm.Circle.select('directory/circle/cenrad')
You can read the current selection using the selection() method. This will
return the replacement-text (or the display-text if replacement-texts were not
defined):
!SelectedText = !This.List.Selection()
The .val member reads the index number of the currently selected value:
!ChosenNumber = !!Form.List.Val
The clear() method will discard both display- and replacement-text lists:
!!MyForm.Colours.clear()
The callbacks for action START and MOVE are not followed by an automatic
update, for efficiency reasons, so you may need to follow some gadget
modifications carried out in the callback with a !gadget.refresh(), e.g. modifying a
TEXT gadget to track the SLIDER’s current value.
The MOVE callback is generated at each step increment in the SLIDER‘s range.
A list gadget allows the user to make single or multiple selections from many
alternatives. The list of choices is scrollable if the list is too long to be
displayed all at once.
A LIST gadget is thus appropriate if you have a long list of choices, or if you are
constructing the list dynamically (at run time), especially if you cannot
predict how many choices there will be.
You must specify whether the gadget is a single or multiple-choice list, and
give the width and height of the displayed portion.
The length defines the number of choices that will be visible within the
gadget. You may optionally specify a text tag to be displayed at the top-left
above the gadget, the position on the form and a callback command.
Typically you enter text values into the list using an array of strings and
assigning to its Dtext member.
More examples:
As with the option gadget, the list gadget actually contains two parallel lists,
of the same length, one containing display values (Dtext) and the other
containing replacement values (Rtext).
The Dtext values must be supplied, but the replacement values are optional.
If you don’t supply the Rtext values they will default to the Dtext values. The
Rtext values are often used to assign callback strings to each field of the list.
Resetting a list gadget's display-texts automatically deletes the existing
display and replacement-texts and clears any current selections. For example,
the contents of gadget List of Figure 20-3 could be replaced by:
!Choices[ 1 ] = 'Tea'
!Choices[ 2 ] = 'Coffee'
!Choices[ 3 ] = 'Chocolate'
!This.List.Dtext = !Choices
You can replace the list’s Rtext with a new array of the same length without
disturbing the current Dtexts:
!newRtext[1] = ‘drink6’
!newRtext[2] = ‘drink4’
!newRtext[3] = ‘drink12’
!This.List.Rtext = !newRtext
At PDMS 11.6.SP1 you can use the new Add methods to add a single new
entry to be appended to LIST and SELECTOR gadgets:
Where Dtext is the text to be displayed in the option list, and Rtext is the
replacement text for the new field.
If Rtext is not specified, it will be set to the Dtext string by default.
Once you make a selection, you cannot interactively unselect a field to return
to the zero selection state.
See the VANTAGE Plant Design Software Customisation Reference Manual
for more information.
!ChosenNumbersArray = !!Form.List.Val
You can read back the current Dtexts or Rtexts as an array or simply as strings:
You can select fields of this list either singly (additive) or by array of Dtext or
Rtext, using its select() methods:
!This.List.select(‘Rtext’, ‘Tea’)
!This.List.select(‘Dtext’, !array)
If you experience a change in behaviour, then you may need to rewrite your
callback to explicitly handle the new START and STOP events and modify the
list content or its selection only on receiving the STOP event action.
For newly written AppWare we strongly advise you use open callbacks to
service multi-selection list gadgets.
list .List |Cars| anchor all columns single zerosel width 25 length 10
The column headings, and hence the number of columns, for the list are
assigned as an array of STRING:
!This.List.SetHeadings( !headings )
The Dtexts for each column of each row of the list can be provided as a PML
array, where each element is an array of STRING. This can be row oriented or
column oriented.
!This.List.SetRows( !rows )
!rows is an array of ‘row arrays’, and its size determines the number of rows
in the list.
!This.List.SetColumns( !columns )
!columns is an array of ‘column arrays’, and its size must match the number
of columns of the list. The size of all the column arrays must be the same and
determines the no of rows in the list.
The default width of each column is determined by the longest header or Dtext
value supplied. Rtext values for each row are supplied as for single column
lists.
Selection within the list applies to the entire row not individual cells, but
rows of the list can be selected on the basis of a column’s Dtext:
This selects the first list row whose column has the given Dtext. If the list is a
multi-choice list then repeated use of this method will add selected rows to
the list.
Note: For a multi-column list gadget each row’s Dtext string is held as
a ‘horizontal tab’ character separated string of column data,
matching the column headings (as opposed to a simple string for
single column list). The standard list members val, Dtext,
Dtext[n] and methods Select( ‘Dtext’, …), Selection( ‘Dtext’ )
work on multi-column lists with the following limitations:
• Querying Dtexts will return the tab separated strings.
• Supplying Dtext to populate the list or invoke selections
will require tab separated strings as input.
See the VANTAGE Plant Design Software Customisation Reference Manual for more
information.
List gadgets with a popup menu assigned to them will pop up the menu when
the right-mouse button is released when the cursor is over the list title or any
list selection field.
For multi-column lists right-mouse in a list field will first select that field,
and unselect any other selected fields, before the popup appears. This
selection behaviour does not occur for single column lists.
The use of popup menus on list gadgets can be confusing so use them with
care.
!element = !This.Members.selection()
Note that for a selector gadget, the Rtext and Dtext are always the same as one
another.
A text gadget is a box that can display a value and into which the user may
type a value, or edit an existing value.
To type into a text gadget on a form it must have the keyboard focus to
receive the keystrokes typed by the user. The user can move the focus to
another text gadget by selecting it with the mouse or stepping from one
gadget to the next using the TAB key.
You must:
• Specify the WIDTH, which determines the maximum number of
character spaces visible. Optionally you may specify a larger SCROLL
width, which is the maximum number of characters that the gadget
can hold, and scroll through. The default scroll-width is 132
characters. The maximum is 256 characters.
• Specify a data type using IS which determines how a value assigned
to the gadget will be displayed and how a value typed by the user
will be interpreted by your PML code. You may also supply a FORMAT
object which specifies in detail how a value is to be displayed or
interpreted (see below).
When you type into a text gadget its background color changes from white to
beige to indicate that has been modified. Its content is actioned when you
press Enter while the text gadget has focus, or if you press a button on the
form.
When a field is actioned its content is read and validated according to the
field’s type (see Section 20.12.5). If an error is detected, then the field’s
background colour changes to gold to indicate an error and focus is returned
to it so that the user can correct the error. If no error was detected then the
text gadget’s callback (if any) is executed
To get the current value of a text input gadget:
!Value = !This.name.val
The data type of the variable !Value will be the same as the type of the text
gadget. To get the textual value use:
!string = !Value.String()
!This.name.SetFocus()
seteditable( !x is BOOLEAN )
!This.name.seteditable( false )
Currently the only attribute supported is HANDLEMOIFY which may have the
integer values:
• 0 MODIFIED events off (default).
• 1 Generate MODIFIED event at first user modification only.
Note MODIFIED events are not notified to PML unless the field is editable,
modified events are enabled and an open callback has been specified
(so that MODIFIED and SELECT events cannot be differentiated).
Typically, the first MODIFIED event is used to allow AppWare to gain control
and modify the properties (e.g. ACTIVE status) of dependent gadgets, which
possibly the user should not have access to until the text field’s VALIDATE and
SELECT events have been handled.
The code fragment below defines an RTOGGLE that allows a user specified TV
program to be typed into an associated TEXT gadget.
The text gadget supports the standard copy and paste mechanisms:
• Use the mouse Select button to copy and the mouse Adjust button to
paste.
• Use shortcut keys, for example: Ctrl C to copy, Ctrl V to paste.
• Use the system Edit popup menu
Pasting into a field acts like typing in, and will set the text field’s Modified
appearance.
Note that user defined Popup menus are not supported on Text gadgets
because they clash with the system-supplied Edit menu.
!!Form.Dist.val = 3505.2
For example:
Note that in every case the text field value is actually held in millimetres so
that the command
q var !!Form.Dist.val
prints
3505.2.
You can use the format object in your PML code when converting a value to a
STRING:
!StringValue = !!Form.Dist.val.String(!!RealFMT)
Note: Some older style ‘untyped’ PML1 text fields use the (null) string
‘’ to represent unset values for numeric fields. You should avoid
using these old style fields
You can force an unset value for any text field (of any type) using:
!Ths.MyTextclear()
You can check for an unset text gadget of any type using the BOOLEAN method
unset():
When a text input field is actioned (by modifying it and pressing ENTER, or
when a button on the form is pressed or the form's OKcall is executed), it is
automatically checked to ensure that the typed-in value matches the field's
TYPE and its FORMAT constraints. If so, then the user's VALIDATECALL is actioned.
The VALIDATECALL is used to apply any checks you want. If an error is
encountered then the callback raises the error and returns.
Note: The validation callback must not attempt to change the value of
the text field. It should just detect and raise an error.
When an error is raised, an error alert is displayed and the text field is left
with keyboard focus and error highlight. No further form or gadget callbacks
are executed and the form is not dismissed from the screen. The User can
then modify the field and re-action it.
The VALIDATECALL is a standard callback, and so it can be a single command, a
PML function, method or macro, or an open PML method or function. For an
open callback, for example:
!textField.validateCall = ‘!this.textvalidate(‘
The form !!ValidForm has two text fields of types REAL and STRING.
There are limits on the values that can be typed into each field: the tooltips
on each field explain the constraints.
The textvalidate method determines from its !textin parameter which field is
being validated, and applies the constraints that have been defined. The
Handle block traps any unexpected PML errors generated by the validation
code. The first if-block of the validation code checks that the text field is not
unset. This also prevents the possibility of unexpected errors in the validation
code.
label /Errors
-- Include handle block for any unexpected PML errors
handle ANY
-- Example: can get errors from evaluation of the String field
-- with an 'unset'value
return error 1 'Invalid input'
endhandle
endif
endif
endif
endmethod
• If the value’s type fails to match the field type, a trappable error is
raised.
• If the types match, the value is validated and the VALIDATECALL is
run, if there is one.
• If the value is invalid then a trappable error is raised. If the field is
shown then it is set 'in error', and the focus is returned to it so that
the user can edit the value.
• If the value is valid then the method executes the field callback if
!doCallback is true.
A textpane gadget provides a box on a form into which a user may type and
edit multiple lines of text or cut and paste text from elsewhere on the screen.
The contents of the textpane can be set and queried by your PML code.
Optionally the text contents can be made non-editable.
You must specify the initial shape of the gadget. Optionally you may also
supply a form position and a tag to be displayed to the top-left of the gadget.
!This.text.seteditable(FALSE)
!This.text.clear()
!This.text.setfocus()
To enquire how many lines of text a textpane gadget currently contains, use
the count method:
!Nlines = !This.text.count
!Line = !This.text.line(21)
!LinesArray = !This.text.val
To set the current cursor position within a textpane gadget to line 21,
character 15 you can use:
!This.text.setcurpos(21, 15)
or
!ArrayRowColumn[1] = 21
!ArrayRowColumn[2] = 15
!This.text.SetCurPos( !ArrayRowColumn )
!ArrayRowColumn = !This.text.CurPos()
Note: Mouse-only copy and paste, and local popup-editing menus are
not supported.
Sometimes you may have large quantities of data in list, selector or textpane
gadgets and you may find that accessing the data using the selection() methods
may be very slow.
The PML textpane mechanism allows fast access to these gadgets.
With a textpane gadget you can use do list so that the do counter takes the
value of the replacement-text for each of the currently selected rows of the list
in turn:
For a selector gadget you must use do selector so that the do counter takes the
displayed value of each of the currently selected rows of the list in turn:
For a textpane gadget you must use do pane so that the do counter takes the
value of each of the displayed lines in turn:
Note that on exit from the loop PML destroys the do variable for each of these
gadget types.
View gadgets are used to display and interact with alphanumeric or graphical
views.
The types of view gadgets supported are:
• ALPHA views for displaying text output and/or allowing command
input.
• PLOT views for displaying non-interactive 2D plotfiles.
• Interactive 2D graphical views
• Interactive 3D graphical views
The command sequence may optionally be given on a single line, without the
exit:
Where the contents and attributes that depend on the type of View.
You do not have to set any attributes and we recommend that you set the
view’s attributes in the form’s default constructor method rather than in the
form setup definition.
!MyForm.MyView.setpopup( !MyForm.pop1 )
Borders and scroll bars cannot be turned off and the area they occupy is in
addition to the size you specify for the gadget.
To define the data channel via which the gadget derives its alphanumeric
content, use the channel command:
!This.InputOutput.SetFocus()
!This.InputOutput.clear()
To delete the ‘requests’ channel from an alpha view gadget us the command:
!alpha.removeRequests()
This command will also dissociate the view from the current PDMS Requests
IO-channel if necessary.
Thus request output will no longer go to this alpha view.
The method is valid only on a form that has been mapped to the screen, and
will cause an error (61, 605) if used during form definition.
Note that you can add the channel back again by assigning to the gadget’s
.channel member:
!alpha.channel = ‘Requests’
This adds the ‘requests’ channel to the gadget, and causes it to become the
current PDMS requests region, if the form is mapped, and displaces any
previous association.
When the user clicks on an alpha view it will automatically associate itself
with the PDMS requests channel or the commands channels, or both,
according to its current channel settings.
Both 2D and 3D view types support a set of common members and methods.
Some key ones are described below, before each subtype is dealt with.
For a full list of View members and methods, see the VANTAGE Plant Design
Software Customisation Reference Manual.
View Borders
Note when specifying the aspect ratio for a view that the corresponding ratios
for ISO drawing sheet sizes are 0.7071 for portrait format and 1.414 for
landscape format.
View Colours
Graphical views have two colours associated with them, namely the
background colour and the highlight colour.
These can be set using the Background and Highlight members, either as integer
colour indices or as colourname text strings:
!view.Background = ‘black’
!view.Background = 2
The highlight colour is the colour used to highlight selected items in the view.
You can set it by
!view.Highlight = ‘white’
!view.Highlight = 1
You can get the background and highlight colour indices from the member
variables or you can use the Highlight() and Background() methods that return the
value of the respective property as a name string.
For instance, using the example above:
!colourname = !view.Background()
!colourindex = !view.background
Cursor Types
When the mouse cursor enters a graphical view, the View gadget determines
what cursor type should be displayed for the user, or the representation to be
assumed during a graphical interaction.
POINTER
NOCURSOR
PICK .
PICKPLUS .
CROSSHAIR
Note: The initial cursor type for VOLUME views is a Pointer, and you
cannot re-define this.
You can specify the initial setting for the cursor type in a 2D view when you
define the view gadget.
The default values for initial cursor types for PDMS 2D view types are:
PLOT CROSSHAIR
DRAFT CROSSHAIR
COMPARATOR POINTER
You may use the CURSortype attribute command to set an initial cursor type
within the gadget definition. For example:
Cursor POINTER
The area occupied by borders and scroll bars is within the area you specify for
the gadget If the border is switched off, the actual display area expands to fill
the available space.
When borders are turned off, the plot view becomes fixed and you cannot
zoom or pan within it. This may be useful if you are using plot views as if
they were paragraphs; for example, as decoration or for information.
To define the contents of the view specify the PLOTFILE pathname with the .add()
method.
To remove a plot from the current plot view, use the .clear() method. This will
leave the view empty. If you want to replace the displayed plot with another
one then just re-use the .add() method with the new plot file.
The area occupied by borders and scroll bars is within the size you specify for
the gadget.
To define the colour items are displayed in when picked with the left–hand
mouse button, use the .sethighlight() method with one of the standard DRAFT
colour numbers or colournames.
The contents of the view may be any valid 2D graphical element, such as a
DRAFT SHEET, VIEW, LIBRARY, etc. To define the contents of the view, use the put
command thus:
Command Effect
If you put new content into an area view that already contains a drawing, the
original content will be replaced by the new, not added to it.
The maximum limits for the drawing, such that only part of the specified
content is drawn (giving, in effect, a window on the overall content area), may
be set using the limits keyword as above or using the .limits() member in the
form’s constructor method, as follows:
!box[1] = 200
!box[2] = 100
!box[3] = 600
!box[4] = 500
!this.drawing.limits = !box
where the limits define two opposite corners of the required area in sheet co-
ordinates.
For a full list of VIEW members and methods, see the VANTAGE Plant Design
Software Customisation Reference Manual.
The area occupied by borders and scroll bars is within the size you specify for
the gadget.
The contents of the view may be any valid Process and Instrument Diagram
sheet reference (PID). To define the contents of the view, use the put
command:
put /A-314
put AREA 34 Doc 2 Shee 1
If you put new content into a COMPARE view that already contains a drawing,
the original content will be replaced by the new, not added to it.
The maximum limits for the drawing, such that only part of the specified
content is drawn (giving, in effect, a window on the overall content area), may
be set using the limits keyword as above or using the .limits() member in the
form’s constructor:
!box[1] = 200
!box[2] = 100
!box[3] = 600
!box[4] = 500
!this.drawing.limits = !box
where the limits define two opposite corners of the required area in sheet co-
ordinates.
For a full list of View members and methods, see the VANTAGE Plant Design
Software Customisation Reference Manual.
The area occupied by borders and sliders is within the area you specify for the
gadget.
To enable colour-shaded representation use the .shaded() method. By default a
wireline representation .shaded(false) is used.
All aspects of the 3D view transformation may be specified:
To enable PERSPECTIVE mode use the .projection(‘PERSPECTIVE’) method. By default
the projection is PARALLEL.
The view direction is controlled via the 3D view’s .direction member. This is a 3
element array of REAL, representing a direction vector in model space ( DEAST,
DNORTH, DUP ). So to look east you would specify:
!dir[1] = 1.0
!dir[2] = 0.0
!dir[3] = 0.0
!this.model.direction = !dir
The centre of interest or through point of the 3D view is controlled via the
.through member. This is a 3 element array of REAL, representing a position in
model space (EAST, NORTH, UP).
!thru[1] = 1000.0
!thru[2] = 5600.5
!thru[3] = 500.0
!this.model.through = !thru
The .radius() method specifies the radius of the view in current units - an
imaginary sphere around the through point.
The .range() method specifies how far away from the Through point you want
the Eye point to be.
To enable WALKTHROUGH mode specify .walkthrough(true) together with the walking
step size in current units using the .step() method.
For a full list of View members and methods, see the VANTAGE Plant Design
Software Customisation Reference Manual.
The commands below allow aspects of the view transformation to be set using
the old syntax:
Modifier Effect
Modifier Effect
View Limits
Each volume view needs to know what region of the design model is to be
displayed (the 3D view limits). The DESIGN application has the notion of a
current limits box. Unless you specify otherwise, the limits set for a new view
gadget will default to the DESIGN current limits box (as set by, say, the LIMITS or
AUTOLIMITS commands in DESIGN).
In addition, each volume view has an AUTO flag associated with it, which
determines whether or not that view will be updated automatically whenever
the DESIGN current limits box is changed.
To define the view limits and the way in which they are to be updated, use
the old syntax:
followed by one of
Modifier Effect
You can set the limits box for a view, subject to the current AUTO flag using
the .limits() method:
-- limits brick set as array of REAL [E1, E2, N1, N2, U1, U2]
!brick[1] = 1000.0
...
!brick[6] = 1560.4
!this.model.limits( !brick )
In DESIGN you may change the current limits box at any time by using one of
the command formats
Any volume views which have LIMITS AUTO set will be redrawn to match the
new limits.
Mousemode
3D views have a mousemode member which can be set to Zoom, Pan, Rotate, or Walk
3D views have two methods which are used to save and restore up to four
views, until the user leaves PDMS DESIGN:
!!view.saveview( !n )
!!view.restoreview( !n )
Note: Alerts are always blocking: they prevent interaction with any
other form until they have been actioned.
Below are some examples of how you can define different kinds of alerts:
Code Effect
Code Effect
!Answer = !!Alert.Input( ‘Type Item code: ’,'P10101' ) Displays an input alert at the
current cursor position:
The first string appears as the
prompt, and the second string
is the default entry in the text
box if the user does not supply
a value.
This shows the alert with its origin one quarter of the way across from the
left hand side of the screen and one tenth of the way down from the top.
!prompt is displayed to prompt the operator and !default is offered as the default
value in the alert’s text input field.
Xpos, Ypos define the alert’s top left hand corner in normalised screen co-
ordinates.
Note that this function has been added to provide the GUI equivalent of the
command
Var !x read
The FMSYS object (Forms and Menus System object) is a mechanism for
providing methods which are not specific to the standard objects, such as
forms, gadgets, menus etc. The FMSYS methods perform a variety of system-
oriented tasks.
The FMinfo() method returns an array of all current Forms and Menus’
information strings:
!info = !!FMSYS.FMinfo(true)
Method Purpose
!form = !!FMSYS.main () Returns a variable of type form, which is
unset if there was no main form
!formsarray = !!FMSYS.forms() Queries all user-forms (excludes main
form and any system forms. Returns an
array of FORM.
!formsarray = !!FMSYS.shownForms() Queries all user-forms which are
currently displayed (excludes main form
and any system forms).Returns an array
of FORM.
Sometimes a callback may take a long time to complete. You can add a stop
button which can be pressed to interrupt the callback, for example, if the
user realises that the form was not filled in correctly, and does not want to
wait until processing is complete.
In your callback function you must first notify the system of the identification
of the stop button using the FMSYS method SetInterrupt:
!!FMSYS.Setinterrupt( !this.StopButton )
Then at an appropriate point in the callback, check to see if the stop button
has been pressed using the FMSYS Interrupt method, and exit with a message if it
has:
do !next from 1 to 50
...
!!RoutePipe( !next, . . . ) $*Route next pipe
...
-- Check if user pressed interrupt button
if ( !!FMSYS.Interruppt() ) then
return error 1 'Processing aborted'
endif
enddo
You can refresh all View gadgets using the Refresh method:
!!FMSYS.Refresh()
By default, when a form is loaded, all the references from it to other forms are
checked to make sure that the other forms exist. If you are experiencing
performance problems, you can switch the reference checking off using the
CheckRefs method:
!!FMSYS.CheckRefs( true )
There are occasions when the PDMS entry screen, known as a splashscreen,
may be left on the screen when PDMS fails to start up, for example, if it has
not been correctly installed, or there are network problems.
To ensure that this screen is removed from the display, you can use the
SplashScreen method:
! !FMSYS.SplashScreen( false )
By default, MDI forms are placed at the maximum (right-hand side) of the
main PDMS window and dialog forms are placed at the minimum (left-hand
side) of the PDMS window.
To switch off default positioning, use the DocsAtMaxScreen method:
!!FMSYS.DocsAtMaxScreen( false )
This method may be useful for wide screen and twin screen devices
!!FMSYS.currentDocument( ) is FORM
!myDocument = !!FMSYS.currentDocument()
At PDMS 11.6.SP1 The FMSYS object has been extended with a new method
LoadForm that allows force loading of a form definition and/or the ability to get
a reference to a form object by name.
The method’s signature is:
If the form exists then the method returns a reference to the form object. If it
doesn’t exist, then an attempt is made to force load its definition.
If this fails then an unset form reference is returned. You can check for this
using the Unset method on the form object.
Warning: These mechanisms are still being developed and so may change
at future releases of PDMS. Even though we will make every
effort to preserve the validity of added-in functional code, we
recommend you isolate the definition of PML Add-ins from the
functional code of your applications to minimise the impact of
any such changes.
Object Description
23.1.2 Callbacks
Each application can now have different types of callback, which are run at
different times:
Key Description
Name The unique identifier of the add-in, e.g. GEN, DES. This
key is compulsory.
Title Text description of the add-in (if the add-in defines an
application, the title appears in the title bar of the main
window when the application is loaded)
ShowOnMenu Determines whether the add-in has an entry on the
Applications menu, i.e. whether the add-in defines an
application (false by default).
Object Add-in object: user-defined object type used to help define
the add-in, e.g. APPGENERAL
ModuleStartup Callback run when the PDMS module first starts
The following keys are only used for applications, i.e. add-ins that have a
menu option on the Applications menu and can be switched to.
Key Description
Key Description
where APPNAME is the name of the application to modify and callback is the
callback to be assigned to it.
If an application with name APPNAME is not defined, the callback is not run.
23.1.5 Initialisation
The add-in definitions are loaded from file during PDMS startup using the
function !!appReadAppDefns(!module is STRING), where !module is the 3-letter
identifier for the module.
This creates the global !!appCntrl object, which holds information about the add-
ins.
After reading the definitions of all add-ins, !!appCntrl assigns all callbacks to the
applications.
For backward compatibility, if an add-in is an application, a directory is
specified for the application and the file module\directory\INIT exists, then this file
is added as a startup-call. Similarly, if the file module\directory\ISYSTEM exists, it
is added as a switch call.
23.2 Menus
Each add-in is able to specify menus that can be shown, along with the
application in which they can be shown. Menus are created by running the
.modifyMenus() method of the add-in object when PDMS first starts.
This associates the object with the menu named menuName on the main
form, creating the menu if it does not already exist.
Add items to the menu using the methods of the APPMENU object.
The arguments for these methods are exactly the same as the menu creation
functions provided by PML. PDMS 11.6 adds support for a unique fieldname
for each field in a menu.
You may specify a field name when adding menu items in this way; if no field
name is specified, then the Dtext of the menu field is used as the field name. To
add to the end of the menu, use the commands
Note: If a menu field with the same field name is already present, the
field will not be added. This is so two add-ins can define the
same menu field, and it will appear independently of whether
one or both add-ins are present.
This method does not always add an item to the end of the
menu. If a function tries to add a menu field with the same field
name as one that’s already present, the next menu field created
(unless it’s inserted explicitly before or after another field or it’s
a separator) will appear after the existing field. The reason for
this is to preserve the intended order of the fields.
!appMenuCntrl.addMenu('APP', !menu)
This automatically associates the object with the bar menu on the main form.
You can then change the contents of the bar menu using the following
commands.
Command Description
!bmenu.add(!dtext is STRING, !menuName is Adds a menu to the end of the bar
STRING)
menu, use the command. This
adds the menu !menuName to the
bar menu with label !dtext.
The menu is automatically
positioned before the Window and
Help menus if they are present.
!bmenu.insertBefore('<TargetMenuName>', To insert menus relative to
'<Dtext>', '<MenuName>')
existing menus, use
!bmenu.insertAfter('<TargetMenuName>',
'<Dtext>', '<MenuName>')
!bmenu.remove(!menuName is STRING To remove the menu menuName
from the bar, use
!!appMenuCntrl.addBarMenu('APP', !bmenu) Register the APPBARMENU object
with !!appMenuCntrl, specifying the
applications in which the menu
should be visible.
23.3 Toolbars
Toolbars are defined by creating a frame of type toolbar on the main form,
using the following syntax.
It is not possible to add toolbars to a form once it has been created, so all
toolbars must be defined before any application is started. The method
.modifyForm() of the add-in object is run during building of the form so that each
add-in can add its own toolbars.
where !toolbarName is the name of the toolbar frame, !appName is the name of the
application to register the toolbar in and !visible is whether the toolbar is
visible by default.
Instead of registering a toolbar in multiple applications individually, an array
of applications can be specified:
where !toolbarName is the name of the toolbar and !visible is whether it is visible
by default.
The command
!!appTbarCntrl.addToolbar(!toolbarName is STRING)
Any toolbars on the main form that are not registered are automatically
detected and hidden by default. They are registered to be active in all
applications.
23.4 Forms
The command
!!appFormCntrl.registerForm(!form is FORM)
!visibleInApps[1] = 'APP'
!!appFormCntrl.registerForm(!form, !visibleInApps, ARRAY(), false, false)
The form will be hidden when switching from the application 'APP' and will
not be shown next time the application is started.
The contents of the array !data will be the strings in the array returned by the
.saveData method when PDMS exited. If no data has been stored for that form,
it will be an empty array
You can also use the command:
if only the name of the form that stored the data is known.
Note: The form must be able to cope if no data is returned. This will
happen the first time PDMS is run or if the form was not open
the previous time the user exited PDMS
The following example shows a form that stores the state of some of its
gadgets between PDMS sessions.
to the main form explicitly rather than using the keyword !this, which will
refer to the object.
Toolbars can be registered – see section 23.3.1 – any unregistered toolbars
will be hidden by default and will not be controlled.
where !module is the name of the module in which the add-in is used,
!appNameStr is the name of the application (e.g. ‘PIPE’), !outputDir is the directory
in which to put the add-in object and !addinFileDir is the directory in which to
put the add-in file.
Then run the .convert() method of the object to perform the conversion:
!convert.convert().
This creates the add-in object and corresponding add-in file. Information
about the existing application is stored in the
%PDMSUI%\module\DFLTS\APPLICATIONS file. This information is read and used to
create the add-in file. Therefore, the application being converted must have
an entry in the APPLICATIONS file in the current PDMSUI path.
Register the APPMENU object with !!appMenuCntrl, so the menu is visible in the
Pipework application
!!appMenuCntrl.addMenu(!menu, 'PIPE')
The same method can be used to add fields to any menu descended from the
bar menu of the main form.
A sample add-in object definition, which must be put in the PMLLIB path, is
shown below.
Name: ADDQUERYMENUFIELD
Object: APPADDQUERYMENUFIELD
!menu.remove('CE')
Register the object with !!appMenuCntrl so the menu item is replaced in all
applications.
!!appMenuCntrl.addMenu(!menu, 'ALL')
The callback of the Delete button on the main toolbar can also be modified.
!!appDesMain.mtbDeleteCe.callback = '!!customDelete()'
A sample add-in object definition, which must be put in the PMLLIB path, is
shown below.
Name:CUSTOMDELETE
Object:APPCUSTOMDELETE
PDMS is constantly evolving and improving. When we add new methods and
properties, some existing methods and properties become obsolescent, and
whilst they will still work in the same way as before, using them for new code
is deprecated. We mark these features as superseded.
We been very careful to maintain compatibility, but in some cases we have
changed or removed existing functionality, in which case if you have code that
relies upon it, you will have to change it.
At any product release we may issue either of the following deprecation
notices:
Notice of Replacement
Reasons:
Notice of Removal
Reasons
Deprecated Feature
Reselection of the already selected field causes a SELECT event, and re-runs
the gadget callback.
Better conformance with Windows style GUI. Expectation is that there has
been no selection change, so no action should result. Current offering fails to
show the previous selection in the dropdown list and reselection fails
(sometimes) if the selected field is over a graphical canvas. This behaviour
militates against us enhancing the OPTION gadget to support full Combo type-
in facilities.
We will remove this at PDMS 12.1.
Consequences
Clicking an already selected field will not constitute a change of value. The
effect is that the gadget callback will not be run (a SELECT event is not notified
to PML).
Possible workarounds:
Deprecated Reature
Reselection of the already selected field causes a SELECT event, and re-runs
the gadget callback.
Better conformance with Windows style GUI. Expectation is that there has
been no selection change, so no action should result. Current offering is
inconsistent as it works for single column lists but not for multi-column lists.
We will remove this at PDMS 12.1.
Consequences
Clicking an already selected field will not constitute a change of value. The
effect is that the gadget callback will not be run (a SELECT event is not notified
to PML).
Possible workarounds
Deprecated Feature
This has become unsafe because many system PML objects are core-code
based rather than pure PML and these cannot be saved and restored by the
PML binary-dump.
Increasingly, Form, Menu and Gadget objects hold instances of such PML objects
and so also cannot be restored correctly.
Other software vendors do not support the ability to completely save and
restore the application state at any point during a session – it is generally
much too difficult.
We will remove this at PDMS 12.1.
Consequences
In particular it is unsafe to use Save and Restore in conjunction with the new
Undo/Redo facilities at 11.6SP1. PDMS11.6 introduced layout preservation,
which ensures that a session starts up with the same forms and layout that
were present at the end of the last session.
The content of graphical views can be saved and restored using .disp files
which are independent of .bin files, so the binary save and restore mechanism
is not now essential.
Deprecated Feature
This gadget has been deprecated and has not been documented for several
years.
We will remove this at PDMS 12.1.
Consequences
Replace any remaining instances with the new FRAME and RTOGGLE gadget
based radio group, which includes identical features and should offer a simple
upgrade path as described in Section 20.6.
Deprecated Features
Methods
The ClickPop() method is no longer supported.
We will remove this at PDMS 12.1.
Menu Gadget
The following methods and properties on the Menu gadget will still work but
are now deprecated because they do not allow internationalization of the user
interface. You should replace them with the new methods using named fields.
Methods
Method Purpose
Properties
Method Purpose
Bar Gadget
The following methods and properties on the Bar gadget will still work but
are now deprecated:
Methods
Method Purpose
1. The start position for an OPTION gadget has moved left by 1 grid
unit.
2. The width of an OPTION gadget with unspecified width and content
has decreased.
3. The extent of a TEXT gadget with no tag has decreased by 1 grid
unit.
4. The extent of an RGROUP gadget set by a long title (rather than by
the size of its included buttons) has decreased.
Deprecated Feature
The button gadget method !button.val now returns type BOOLEAN rather than
type STRING.
Consequences
None.
Deprecated Feature
The ability to assign a user defined Popup menu to the TEXT gadget has been
withdrawn, because it clashes with the default ‘Edit’ popup which allows
standard cut, copy and paste actions on the text field.
Deprecated Features
Popup-Menu Trees
Menus in the popup menu system can be called from different popup trees,
but cannot be used more than once in a single popup tree.
Infringing this will cause an error alert to be raised.
Deprecated Features
Changes in Layout
You must now explicitly set the spacing between radio buttons within the
RGROUP gadget rather than allowing it to be derived from the VDIST and HDIST
setting in operation at the point of definition.
This material is chiefly for AVEVA developers and not users, because it
requires cooperation between AppWare and core-software.
The mechanisms described below allow PML defined forms, menufields and
gadgets which are subsequently managed by core code. It should be noted
that the use of core code managed forms, menufields and gadgets requires
well planned co-operation between software and AppWare.
It is permissible to have a mixture of PML and CORE managed gadgets on a
PML managed form.
A CORE managed form may also have some PML managed gadgets and
menufields, but extreme caution should be adopted in this case. Making a
form core managed involves considerable effort in the supporting core code, as
it bypasses most of the F&M form management support.
PML defined forms now have a new qualifier attribute ‘control type’, with
values PML or CORE. A form is PML managed by default, but can be
declared core managed by means of the ‘CORE’ keyword in the FSETUP
command. This is applicable to any form type except MAIN forms, for example:
In general the PML form definition for a core managed form should not define
the following PML callbacks:
• INITCALL
• AUTOCALL
• OKCALL
• CANCECALL.
If OK, CANCEL or APPLY buttons are present they should also be declared as
CORE managed.
CORFRM ( int FORM, int WMID, int FTYPE, int LSTR, string FORMNAME )
where:
The following F&M routines will be useful for core code management of PML
forms with core managed gadgets:
Command Effect
FLDFRM ( int LNAM, string FNAME, int FORM ) Load named form from a
definition file. FORM is a handle to
the created form object.
FDSCOR ( int FORM, int IERR) Display the given form. IERR is a
PML error token. It takes the
value 0 when there was no error.
FHDCOR ( int FORM, boolean CANCEL ) Hide the given form. If CANCEL=true
it means the form was cancelled.
Otherwise it was OK’ed
PML defined forms may now have a mixture of PML managed and core code
managed gadgets.
A new gadget qualifier attribute ‘control type’, with values PML or CORE has
been introduced.
The following gadgets can be declared to be CORE controlled or PML
controlled during their definition:
• BUTTON
• TEXTIN
• TOGGLE
• PARAGRAPH (doesn’t have a callback)
Alpha and Graphical view gadgets are not candidates for this mechanism.
These gadgets’ definition graphs now support the ‘CORE’ qualifier:
.-------<---.
/ |
<gadget>--+-- tagtext --| gadget tag
| |
+-- <fgpos> --| gadget position
| |
+-- CORE -----| Core managed gadget
| |
.
.
.
When a form is first displayed its gadgets are created. If a gadget is declared
as core managed then F&M, builds the DRUID widget, sets its active, visible
and selected states, and then calls core code to allow it to take over the gadget
callback.
Core code may plug in its own callback function to DRUID so that events on
that gadget will go directly to core code and will no longer go to F&M. Core
code will then be responsible for managing the gadgets state in conjunction
with PML AppWare. For gadgets with no callback, the core code may merely
wish to read values from or write to the gadget. You must exercise great care
to avoid clashes between AppWare and software management.
The callbacks on RGROUPS are constrained in that they have one callback
for the entire gadget, and not one for each button; moreover, TEXTPANE and
PARAGRAPH gadgets do not have a callback.
CORGDT ( int GADGET, int WMID, int GTYPE, int LSTR, string GDTNAME )
where:
The element GADGET is owned by an F&M FORM element, so its owner (in
this case the form) element can be obtained from:
The following F&M routines may be useful for core code management
gadgets:
Query immediate owner and owning form of given element ELT (gadget,
menu, menufield etc.)
Where:
• FORM and OWNER are returned arguments.
• FORM/GADGET/MENU/MENUFIELD/ELT/OWNER is the F&M
handle for an element.
• IERR is a PML error token, where 0 means no error.
The F&M menu fields are mapped to DRUID MenuItem widgets at the first
UI_FILL_MENU or UI_UPDATE_MENU event. At this point F&M, builds the DRUID
menufield widget, sets its active, visible and selected states, and then calls
core code to allow it to take over the field.
Core code will plug in its own callback function into DRUID so that events on
that field will go directly to core code and will no longer go to F&M. Core code
will now be responsible for managing the menu field’s state in conjunction
with PML AppWare.
where:
• WMID is the DRUID driver handle for the field. This will allow the
core-code to provide its own callback for the menu item.
• FTYPE is the field type (0-4). These values correspond to the following
types: CALLBACK, TOGGLE, SEPARATOR, MENU, FORM.
• FLDNAME is the core-code/AppWare agreed menu field name string of
length LSTR
F&M will provide the following interface for core-code to manage the
menufield state: Menu field active, visible, checked.
This Appendix tells you how to interact with the 2D and 3D View gadgets.
This section describes the standard mechanisms provided by the Forms and
Menus software for manipulating a 2D view using the mouse buttons, number
keypad and function keys.
• MB2 (adjust)
• MB3 (popup)
If you press MB3 when the cursor is over the view canvas, the popup view
menu is displayed. This will either be the default menu supplied by the
Forms and Menus software, or an application-specific version if provided,
either by AVEVA or by your own customisation.
Note the Reset Limits option on the View popup-menu, which will return to the
initial view limits.
These keys will be particularly useful on, for example, laptop keyboards,
which frequently do not have a numeric keypad:
Key Effect
The view scroll bars enable you to pan across the view:
7 8 9
Pan down by
Zoom in x 1.5 Zoom in x 2.5
half view
on view centre on view centre
width
4 5 6
1 2 3
Each click pans the view by 1 step distance, where a step is half the size of
the current displayed window.
2D views now have 4 view stores that allow storage and retrieval of the
current view state. They can be accessed by the saveview() and restoreview()
methods:
!myview.SaveView( !storeNumber )
!myview.RestoreView( !storeNumber )
This section describes the standard mechanisms provided by the Forms and
Menus software for manipulating a 3D view using the mouse buttons, number
keypad and function keys.
The mouse buttons are referred to as:
• MB2 (adjust)
• MB3 (popup)
If you press MB3 when the cursor is over the view canvas, the popup view
menu is displayed. This will either be the default menu supplied by the
Forms and Menus software, or an application-specific version if provided,
either by AVEVA or by your own customisation.
This Section describes the default menu.
View controls using the mouse are analogue. They work best when the
redraw time is not too large, so that you get rapid feedback. With long redraw
times (large models), you may find that the keyboard digital controls are
easier to use.
The view parameters are displayed in the status line, just below the view. For
example:
Field Meaning
Popup Menu
Pressing MB3 displays the popup view menu when the cursor is over the view
canvas.
This will either be the default menu supplied by the Forms and Menus
software, or an application-specific version if provided, either by AVEVA or
by your own customisation.
Zoom F2
Pan F3
Rotate F5
Walk F6
The Zoom, Pan, Rotate and Walk options select a mouse mode.
The Options pullright toggles the states of Eye/Model, Shaded/Wireline,
Borders On/Off, and Perspective/Parallel.
These actions may also be achieved by pressing the relevant Function Button
while the view canvas has keyboard focus.
The Restore and Save pullrights allow up to four view settings to be saved and
restored. To save the current view settings, choose S1, S2, S3 or S4 from the
Save menu. To restore a previously saved setting, choose R1, R2, R3, or R4
from the Restore menu. These functions are also available using Alt, Ctrl, and
the keypad numerals 1 to 4 while the canvas has keyboard focus.
Mouse Modes
Mode Navigation
Zoom (F2). Press Adjust down over the view canvas, and then,
keeping the button down, move the mouse upwards
to zoom in, and downwards to zoom out.
This changes the perspective angle, or the view
scale in parallel views. It does not change the eye
point or the view direction. Use Ctrl or Shift to
speed up or slow down.
Pan (F3). Press Adjust over the canvas, and then, keeping the
button down, move in any direction to shift the line
of sight in that direction. The current view
direction is not changed.
Note that the picture moves the opposite way to
the mouse movement; it is the observer that is
being moved.
It may be useful to think of moving the mouse
towards the part of the picture you wish to see. Use
Ctrl or Shift to speed up or slow down.
Rotate (F5). Press Adjust and keep it down, then move left/right
to change the bearing of the view direction, or
up/down to change the elevation.
The initial movement of the mouse determines
which is changed, and only that component of the
view direction is modified.
To modify the other component, the mouse button
must be released and then pressed down again,
while moving in the other direction.
Walk (F6). Press Adjust button and keep it down, then move
up to walk forwards, or down to walk backwards,
along the line of sight. Use Ctrl or Shift to speed up
or slow down.
Eye (F7). View rotations keep the from- point fixed, and in
Model mode rotations keep the through-point fixed.
Use Ctrl or Shift to speed up or slow down.
In all modes, clicking MB2 will shift the point under the cursor to the centre of
the view. In perspective, the from-point will be maintained, and the view
direction and through-point will be modified. In parallel, the view direction
will be maintained, and the from- and through-points moved. The only
exception to this rule is in Pan Mode, when the view direction is never
modified.
When the keyboard focus is in the view, the following functions are available.
7 8 9
4 5 6
1 2 3
Key Effect
Function Keys
Key Effect
The arrow keys change the line of sight as in Pan mode, by 1 STEP distance.
Ctrl Arrow does 10 STEPs
Shift Arrow does 1/10 of a STEP.
The following changes have been made to allow consistency with ReviewLE
and to improve usability on 'lap top' keyboards which frequently do not have
the Numeric Keypad.
Notes