Developing CAM palettes
A "palette" is a set of definitions for a specific modelling language in CAM. Each palette in CAM is configured by the files in a subfolder of the "palettes" folder within the main CAM folder. The palette folder name is usually the same as the palette name.
Within a palette folder, there are a number of text files, each of which describes one element in the palette (i.e. one type of node that can be drawn on a CAM diagram). There is also a file called "configuration.def" which gives options for the whole palette (such as whether hierarchical worksheets, resources etc. should be shown).
To define a palette, the basic steps are as follows. For more details see the specific sections below.
- Decide on the name. Palette names must be unique, and should not contain spaces.
- Create a configuration.def file for the palette.
- Create the elements in the palette. This requires creating a palette element definition file for each element, and an icon for each one.
- Create the port classes and the connector classes.
- Finally, set up the rules in the configuration.def file that specify how the palette elements can be connected together.
To make CAM recognise a new palette, the software must be restarted. To see changes to existing configuration files it is sufficient to create a new model in CAM, without restarting the entire software.
Note that all palette elements must have unique names across the whole of the CAM installation. Thus when creating a palette with name XYZ, it is sensible to ensure all element types have names such as XYZElement.
It is also possible to create a new palette by copying and modifying an existing palette. This is the recommended approach, because the syntax is rather complex and, if you make a mistake, there is limited information provided by CAM to debug your configuration.
Thus, a good way to start is to copy an existing palette, then change the palette name and the names of all elements, port classes and connector classes within it to ensure uniqueness. Then, progressively change the configuration of the new palette, testing it out by creating a new model in CAM after each small change.
The configuration.def file
The configuration.def file consists of a number of commands setting up the general options for creating models using that palette. It is a text file called "configuration.def" (not "configuration.def.txt" !). At the top of the file there should be the following 3 lines:
framework-name: [The name of the palette, as displayed in the CAM user interface]
framework-uid: [a unique identifier for the palette, using dashes to separate words]
worksheet-color: [the colour associated with the palette - DEPRECATED, the line is required but does not do anything]
Then there are a set of lines setting whether particular modelling aspects can be used, mostly from the top-left "Perspectives" sidebars in CAM (each followed by "true" or "false"):
enable-variables: [whether the variables tree in the sidepane should appear in CAM for models created using this palette]
enable-parameters: [whether the parameters tree should appear in CAM for models created using this palette]
enable-resources: [whether the resources tree should appear in CAM for models created using this palette]
enable-calendars: [whether the calendars tree should appear in CAM for models created using this palette]
enable-subprocesses: [if subsheets/subprocesses can be used in building models]
Finally, there are some commands that define which palette elements can be connected together and, if a connection is created, what the class of that connection should be. Defining connection classes is optional; if used, this allows properties to be assigned to edges as well as nodes in a model.
There are two commands that specify which connector-class (see below) should be used for a connection between a source element and a sink element. These either specify both the classes of the source and sink elements and the names of the port relations (connection-type), or just the names of the port relations (connection-type-port-classes):
connection-type: [source element type] [source element port relation name] [sink element type] [sink element port relation name] [connector class]
connection-type-port-classes: [source element port relation name] [sink element port relation name] [connector class]
It is also possible to prohibit connections between elements, again either by specifying both the classes of the source and sink elements and the names of the port relations (connection-not-allowed), or just the names of the port relations (connection-not-allowed-port-classes).
connection-not-allowed: [source element type] [source element port relation name] [sink element type] [sink element port relation name]
connection-not-allowed-port-classes: [source element port relation name] [sink element port relation name]
If, when constructing a model, the user tries to connect two elements and the configuration.def file neither prohibits the connection nor specifies the connector-class for it explicitly, CAM will create the connection but will leave it as a "Palette element default connection".
Defining elements in the palette
Each type of element in the palette is defined by a text file (with the extension .txt) in the main directory of the palette (not in any subfolders). The file is divided into several sections, each indicated by a heading line which starts with a colon (":").
General information (heading ":class")
This section has only 2 commands, both of which are obligatory:
class-name: [the name of the type of element]
class-icon: [the name of an image file to be used in the toolbar in CAM - this should be a 16 pixel square GIF, in the same directory as this file]
All palette elements must have unique names across the whole of the CAM installation. Thus when creating a palette with name XYZ, it is sensible to ensure all element types have names such as XYZElement.
Properties (heading ":properties")
This section lists the properties that can be assigned to an element. Basically, it is a list of property definitions of the form:
property-name: [name] [default value]
property-module: [name of the module used to implement it - see below]
Again, the name of the property must be unique and is used to refer to it elsewhere, while the property module defines the type of information the property can store (a text string, a true/false value, a number etc.). The default value of a property can be set using the [default value] parameter - the syntax for this depends on the property module used. If the name or the default value contain spaces, they must be enclosed inside quotes.
Certain property modules need an "initialiser" to set them up correctly. This is done by adding an extra line after the property-module line:
property-initialiser: [a string used to initialise the property]
Some of the common property modules in the default distribution of CAM are:
- p3-single-line-string-property: an ordinary text box - [default value] is just the default contents of the box.
- p3-multi-line-string-property: the same but multi-line.
- p3-boolean-property: a checkbox, where [default value] can be "true" or "false".
- p3-list-selection-property: a drop-down list/"combo box". This takes an initialiser rather than a default value - see below.
- p3-color-property: a colour, which can be specified in RGB form using [default value] as "[R],[G],[B]" (each in the range 0-255) e.g. black = "0,0,0"
- p3-font-property: how a text string is displayed, which can be specified using [default value] as "[font name],[style],[size]" e.g. "Arial,0,9". Styles are represented by a number: plain = 0, bold = 1, italic = 2, bold italic = 3.
The initialiser string for the list-selection-property should be a string as follows (including the quotes!):
"<initialiser class=''p3.dflt.property.P3ListSelectionPropertyInitialiser''><option>[first option]</option><option>[second option]</option>[repeat the <option>...</option> pairs as many times as needed]<value>[the default value - should be one of the options specified previously]</value></initialiser>"
And some of the less-commonly-used property modules in the default distribution:
- p3-value-in-range-selection-property [minimum],[default value],[maximum]
- p3-bounds-property
- p3-code-property
- p3-date-property
- p3-image-property
- p3-long-property
- p3-object-property
- p3-range-selection-property
- p3-syntax-highlighting-code-property
However, property modules are, as the name suggests, modules - thus it is possible to write a new module if you need some functionality that is not already present.
Relations (heading ":relations")
This defines the element's "port relations" through which it can be connected to other elements - a single palette element may, in general, have several port relations (for instance, separate port relations for inputs and outputs). Each port relation is defined through a sequence of 4 lines:
relation-name: [a name for the port relation, again in quotes if necessary - different port relations must have different names!]
relation-sink-class: [the port class to use - this must be one of the port classes in the palette, defined as described in "Port classes and connector classes" below]
relation-min-sinks: 1
relation-max-sinks: 1 [leave these two lines just like this]
Commands specifying how to draw the element on a worksheet (heading ":render-node")
Within a text file defining an element, the following rendering commands are recognised:
- draw-rect: [top left x] [top left y] [width] [height] [colour]
- fill-rect: [top left x] [top left y] [width] [height] [colour]
- draw-oval: [top left x] [top left y] [width] [height] [colour]
- fill-oval: [top left x] [top left y] [width] [height] [colour]
- draw-line: [x1] [y1] [x2] [y2] [colour]
- draw-polygon: [x1] [y1] [x2] [y2] […] [colour]
- fill-polygon: [x1] [y1] [x2] [y2] […] [colour]
- draw-string: [x] [y] [anchor] [string to draw] [font display options] [text wrapping width].
Some notes:
- In coordinates, x increases from left to right and y increases from top to bottom.
- Commands are executed in the order specified in the file - thus later commands are "drawn on top of" earlier commands.
- All polygons are closed, even those defined with draw-polygon.
- For text, the anchor must be one of NORTH, WEST, SOUTH, EAST or CENTER – it specifies which edge (or centre) of the string’s bounding box touches the specified point
- At the moment, the only things in the rendering command definitions that can be specified directly (as "literals") are coordinates, heights/widths, text anchor points and text wrapping widths. Anything else (colours, text strings and font display options)must be specified indirectly, through referring to the name of a property that holds the value - for instance, "draw-line: 0 0 10 10 Display.Line.Color".
- As in the property definitions, the names of properties that are referred to in the rendering commands must be in double quotes if they contain spaces.
And some advanced features:
- In order to draw shapes that adapt to the size of a text string, for instance text inside a rectangle which resizes to contain it, put the command "prepare-string: [x] [y] [anchor] [string to draw] [font display options] [text wrapping width]" (syntax as for draw-string) at the beginning of the string of rendering commands. Then, define the rest of the rendering commands as if the text box was a single point (i.e. a rectangle of zero width and height) located at (x,y). When the node is drawn, the point (x,y) will be "opened out" and the surrounding elements will be resized accordingly. The anchor has a slightly different meaning from draw-string: if there are features of otherdrawing elements (e.g. a corner of a rectangle) that are located directly above, below or on either side of (x,y), the achor specifies what happens to them when the element is drawn.
- It is possible to specify detachable "groups" of rendering commands that can be moved around separately relative to the base palette element (e.g. for the name label). To do this, put a name forthe group in brackets on a line before the commands to be detached. The convention is to use "(text)" for the name label. The commands directly after the ":render-node" heading are assumed to define the basic shape, and are fixed.
- To make a node's display vary depending on the values of its properties, put the line "condition: [property name]=[value]" before a set of rendering commands to ensure they are only executed if the specified property has the specified value. The commands directly after the ":render-node" heading are always executed.
Ports (heading ":node-ports")
This specifies how the port relations defined in the ":relations" section are actually drawn on the diagram. It consists of a sequence of lines that map each port relation to a geometrical shape:
[command]: [parameters] [directionality] [port relation name]
Note that the shapes are not drawn themselves - control over rendering the node is all done through the commands in the ":render-node" section.
[command] can be one of:
- rectangular-node-port - parameters [x] [y] [width] [height]
- elliptical-node-port - parameters [x] [y] [width] [height]
- polygon-node-port - parameters [x1] [y1] [x2] [y2] [...as many pairs of coordinates as necessary!]
Finally, [directionality] can be:
- IN - port accepts incoming connections only
- OUT - port accepts outgoing connections only
- INOUT - port accepts incoming and outgoing connections
Port classes and connector classes
The palette defines not only the types of element in a modelling language, but also types of connector (the arrows between elements) and types of "port". Again, each is defined by a text file in the appropriate subdirectory of the palette folder: "classes" for port classes, "connector-classes" for connector classes. In general, all elements in a palette can and should use the same port class.
The syntax for the files are subsets of the syntax used for defining palette elements (see above). In the case of the port classes, only the first section of the file (the ":class" section) can be used, and only the "class-name" command has any meaning - thus, the entirety of the file defining a port class will look somthing like:
:class
class-name: XYZPort
For the connector classes, both the ":class" section and the properties section (":properties") can be used, since CAM allows connectors to have properties in the same way as palette elements. Again, the syntax is exactly the same as the palette element definition files. However, it is important to include the 4 standard properties that are used to control how the arrows are displayed:
- Display.Fill.Color (p3-color-property, sets the colour of the arrowheads)
- Display.Line.Color (p3-color-property, sets the colour of the arrow's "line")
- Display.Font.Color (p3-color-property, sets the colour used for the label text)
- Display.Font.Style (p3-font-property, sets the style used to display the label text)
CAM also allows finer control over the display of arrows (e.g. double lines, open/unfilled/diamond-shaped arrowheads etc.).