Architecture
The Prototypes package is defined on top of the Views Foundation package and allows you to perform the following tasks:
*Assemble elementary graphic objects into groups (class IlvGroup).
*Specify the behavior of your groups using predefined accessor objects or scripts.
*Define prototypes and create prototype instances in managers. Prototypes are instances of a subclass of IlvGroup called IlvPrototype.
*Connect properties between prototype instances.
*Link application objects and prototype instances.
The architecture of the Prototypes package is shown in Architecture of the Prototypes Package:
Architecture of the Prototypes Package
Groups
Groups are the basic components of the Prototypes package.
To create a BGO with the Prototypes package, you must first assemble basic Views graphic objects to build a group. You can use any Views graphic object in a group. You can also create subgroups to build structured objects.
A group is represented in C++ by the IlvGroup class. An IlvGroup object contains a hierarchy of nodes, represented by the following subclasses of the IlvGroupNode class:
*An IlvGraphicNode is a node that holds a graphic object (an instance of a subclass of IlvGraphic). A group contains one graphic node for each of its graphic elements.
*An IlvSubGroupNode holds a subgroup, that is, a group contained in another group. This class is used to create object hierarchies.
Notes: IlvGroup objects are different from IlvGraphicSet objects. An IlvGroup is a logical hierarchy of graphic objects that are contained in a manager. Unlike IlvGraphicSet, IlvGroup is not a subclass of IlvGraphic. An IlvProtoGraphic is a subclass of IlvGraphic intended to encapsulate an IlvGroup to place it in a manager or container.
A third class of IlvGroupNode, called IlvValueSourceNode, is still present in the package, but its use is deprecated.
Attributes and Accessor Objects
The Prototypes package lets you define not only the graphic appearance of your objects, but also their behavior. The behavior of a group is controlled by its attributes (also called properties). These attributes bear distinct names and represent the external interface of the group, that is, how its appearance will be controlled from your application.
The attributes of a group and their behaviors are defined in accessor objects. Each accessor object has a name and a type and implements the effect of setting and/or retrieving the value for the group. Several accessor objects can have the same name, which means they belong to the same attribute. This means that setting an attribute value can have several side effects.
Accessors can be linked to other attributes of objects or to application data. They define state or appearance changes in response to user events or application instructions and, by extension, specify the graphic and interactive behavior of objects. Accessor objects are instances of subclasses of IlvAccessor.
In other words, the relationship between accessor objects and values is the following:
*You interact with a group through its attributes.
*A group has a set of accessor objects attached to it. Each accessor object is associated with a name, which defines an attribute (or facet) of the BGO.
*The IlvGroup::changeValue method calls the changeValue methods of all the accessor objects of a given name, thereby setting the attribute value.
*The IlvGroup::queryValue method calls the queryValue methods of all the accessor objects of a given name, thereby getting the attribute value.
*The effect of each behavior class is defined by the implementation of its changeValue and queryValue methods.
*Some accessors can be set through user interaction or by the application, thereby triggering other behaviors in a chain.
The relationship between accessor objects and attributes/behaviors in a group is shown in Relationship Between Accessor Objects, Attributes, and Behaviors:
Relationship Between Accessor Objects, Attributes, and Behaviors
This example shows a group representing a gauge. The gauge has two attributes: speed and max.
*The speed attribute is implemented by two accessor objects, each having a graphic behavior:
*A Rotation accessor object—when the speed attribute is changed, this accessor object rotates the needle of the gauge.
*A Condition accessor object—when the speed attribute is changed, this accessor object changes the color of the circle if the value is greater than 30.
*The max attribute is implemented by a Reference accessor object, which references a property of a basic graphic object at the group level. When the max attribute is changed, this accessor object changes the maximum speed of the scale graphic object.
The following types of accessors can be attached to an attribute:
*Data accessors - State how a data item is to be stored (locally or in a node) and what its type is. They are comparable to variable declarations in a regular programming language. Only one of these accessors should be present for each attribute.
*Control accessors - Perform conditional instructions, evaluations, and assignments based on other attributes. They take input parameters and can have output effects on other parameters. Typical examples are the Condition accessor, for the conditional assignment, and the Toggle accessor.
*Notifying accessors - Define the entry points of evaluation cycles. Either the application (when it does a pushValue) or the user (when a callback triggers a Callback accessor) can “push” values, forcing the accessors to handle them. Connections between attributes can be made to propagate the evaluation to other values by means of the Watch and Notify accessors.
*Display accessors - Define a side effect of the attribute on the visual presentation of the nodes of the group. They correspond to calls to the drawing library in a programming language. When they are set, they change graphic properties, such as rotating a node or changing the visibility of a graphic component.
*Animation accessors - A special case of display accessors that periodically change a graphic attribute.
*Miscellaneous accessors - Consist of two accessors that do not fit into the previous categories: the Debug accessor and the Delegate to Prototype accessor.
You will find a full description of all the predefined accessor classes in the section Predefined AccessorsPredefined Accessors.
Accessor Parameters
Accessors define a side effect that is performed on another object or attribute when a given attribute is set. This means that, as with a function in a programming language, an accessor has to take parameters to customize its effects. A description of the four types of parameters that accessors can have is presented in Accessor Parameters.
Accessor Parameters 
Parameter Type
Description
Direct parameters
The value is a string or an enumerated type that must be specified explicitly.
Input parameters
The value is queried when the accessor is evaluated. These values can be a constant (a string or a number), a reference to other values (attributes of nodes or prototype values), or an expression that is a combination of constants and references.
Output parameters
The value is changed when the accessor is evaluated (A call to the changeValue method is made). Hence, the value must be a name that references either an existing attribute of a node or a prototype value.
Object/Node parameters
The value of the parameter must be the name of an existing node. Some accessors accept only certain kinds of objects as a parameter. For instance, display accessors act only on graphic nodes.
Input parameter expressions can contain:
*Constants: numeric or string literals
*Variables: prototype values or node attributes
*Arithmetic operators and parentheses: (+, -, *, **, /, %, ==, !=, >, >=, <, <=, &&, ||)
*Predefined functions: abs, acos, asin, atan, ceil, cos, exp, floor, log, rand, rint, round, sin, sqrt, tan
Note: Contrary to its C/C++ equivalent, rand() takes an integer argument. If this argument is non-zero, it is used as a seed for the random generator before a random number is generated. Otherwise, rand(0) returns the next integer in the random sequence started the last time the random generator was initialized.
Prototypes and Instances
Once you have defined the graphic contents and the behavior of a group, you can save it as a prototype. A prototype is the model of a BGO. Usually, you create prototypes with Views Studio, although you can also create prototypes directly by coding. See Creating Prototypes by CodingCreating Prototypes by Coding.
Prototypes are stored, loaded, and saved using prototype libraries, represented by the class IlvProtoLibrary.You can create prototype instances from a prototype. A prototype instance is a full copy of its prototype.
Prototypes are represented by the IlvPrototype class and prototype instances are represented by the IlvProtoInstance class. Both of these classes are subclasses of IlvGroup.
When a prototype instance is saved to a file, the manager writes only the values of the properties that have been modified for that instance. The graphic objects that compose the prototype instance are not saved to the file. This means that you can completely change the definition of the prototype, add or remove graphic objects, and so on. Instances of the modified prototype will be automatically updated with the new definition.
Displaying Groups and Instances in Managers and Containers
To display groups, prototypes, and instances in a panel of your application (an IlvManager or IlvContainer), you need to place them in an IlvProtoGraphic object and add this object to the manager or container. IlvProtoGraphic is a subclass of IlvGraphic designed to encapsulate all the graphic objects of a group. You may also add group objects to a manager using an IlvGroupHolder, which is a class that extends the properties of a container or manager and lets you directly add or retrieve groups through convenience functions.This class will create the IlvProtoGraphic itself to wrap it around the IlvGroup.
Note: Special manager and container classes IlvProtoManager, IlvProtoContainer, and IlvProtoGrapher have been added to allow direct handling of IlvGroup objects in a container or manager. These classes are provided for compatibility reasons. Their use is obsolete and should be avoided.
Connecting Attributes
A group has readable and writable attributes that are defined by the accessor objects attached to it. It can also have notifying attributes, which are similar to events generated by the group or by one of its elements.
A notifying attribute can be connected to an attribute of another group. When the attribute is modified, the changes are propagated to the groups connected to it. This is referred to as the value of the notifying attribute being pushed to its connected attributes.
Linking Application Objects to Prototypes
Once you have defined your prototypes and your panels, you may want to connect these to real application data and processes defined in C++.
There are three methods available to link prototypes to application objects, depending on the type of interface you want to produce:
*When the display is graphics-rich but represents only a few application objects and values, you may want to link the application objects by directly feeding values to the prototype instances of a given panel.
This is typically used in static synoptic displays composed of only predefined graphic components. It is convenient to use feed values directly when the application is not expecting user input to modify application values through a prototype instance. The base_feed sample in <ILVHOME>/samples/protos shows how to use this approach for a simple control panel.
*To build WYSIWYG, direct-manipulation application object editors, you may want to use an IlvGroupMediator. With this class, you can link an application object to a given IlvGroup (or prototype instance) in a panel, allowing interactive editing of its attributes. A group mediator allows you to bind and unbind application objects dynamically to a given prototype that serves as an editor for the object.
A typical application of this type is a WYSIWYG inspector such as the Guides inspector in Prototypes Studio. The inspector sample in <ILVHOME>/samples/protos is an example of this kind of editor. It shows how to build a 2D transformation matrix editor controlling the viewpoint of a view interactively.
*To create many instances of a prototype dynamically, with each instance linked to a given application object, you should use an IlvProtoMediator. This class instantiates the prototype and links it to an application object of a given class as it is created. This allows clear separation of interface design from the application design, each being able to evolve separately from a commonly agreed upon application interface.
A typical application of this type allows you to view panels where many objects of many classes are represented and edited at the same time. Each application class is linked to a prototype and each instance of the class to an instance of the prototype.
Cartographic displays and all graph displays are examples of applications that can benefit from prototypes using IlvProtoMediators. <ILVHOME>/samples/protos/interact_synoptic is an example of this type of application, showing a very simple air-traffic simulator, where each flight and each airport are represented by prototype instances. The simulator only deals with changing the attributes of the flight, whereas the prototypes can be incrementally refined in the drawing editor to present the best display.
Published date: 05/24/2022
Last modified date: 02/24/2022