Presentation Model Overview

This document gives an overview of the main concepts in the Mastermind presentation ontology, and describes how to use these concepts to specify the display aspects of an interface. In Mastermind the process of specifying displays is called building the presentation model for the display. Presentation models are constructed by instantiating elements from the Mastermind libraries and linking these instances together.

In order to understand this manual, you first need to read the manual for the model representation language, which describes what an ontology is, what is meant by instantiating an object, and other fundamental concepts of the modeling process.

The following are the key concepts you need to understand to use the presentation model to build interfaces. The rest of this document describes these concepts in more detail.

Display hierarchy
All displays are constructed as a part/whole hierarchy of presentation elements.
Visual appearance
The visual appearance of each presentation element is defined by its prototype (icon, text, line, group, etc.), and by miscellaneous parameters defined by the prototype to control features such as color, line-style, font, etc.
Connecting displays to application data
Displays are connected to application data by expressions that call application routines. These expressions are the values of attributes of presentations.
Layout
Layouts are specified using grids, guides and expressions that compute the values of guide posistions based on the positions of other guides, of grids, and of arbitrary parameters.
Replication
Replications are the mechanism to specify that a part should be replicated many times in order to display multiple data items.
Conditionals
Conditionals allow the specification of context-dependent presentations, i.e., presentations whose structure and appearance depends on the data to be displayed, on the amount of space avaialble for the display, on the state of the dialogue, and other characteristics.

Display Hierarchy

In Mastermind every display is constructed as a part/whole hierarchy of presentations. Each element in the hierarchy is an instance of class Presentation, and its parts are stored in the parts attribute, which is a multi-valued, part/whole attribute. The parts are also instances of Presentation.

To illustrate the process of building a presentation model, suppose that you want to construct an interface for a database application. This simple interface shows a form with the information contained in one record, as shown in the figure below. A record consists of a list of field name and value pairs, and the interface shows each element using two text fields, one for the field name and one for the value. The field name/value pairs are arranged in a column.

Here is a fragment of the presentation model that shows how the display hierarchy for the form is defined. In the next sections we will elaborate this model to include all the information needed for it to be complete.

Record_Window : MM_Window {
  parts =
    element : Presentation {
                parts =
                  field_name : MM_Label, 
                  field_value : MM_Label;
              };
};

This initial specification says that the window has one part called element, which has two parts called field_name and field_value. Later on we explain how you specify that the element part should be replicated for each field in the record to be displayed. The element part is an instance of Presentation, which does not give it any visual appearance, and the field_name and field_value parts are instances of MM_Label, which is the library component for specifying presentations that show labels.

A presentation is not something that is directly painted on the screen. Rather, a presentation serves as a template for generating widget trees when the application executes. Widget trees are the data structures that directly mirror what is on the screen and are used by the graphics layer to paint on the screen. As an interface developer, you never specify widget trees directly. You specify presentation objects from which Mastermind generates the widget trees.

By removing you one level from the widget trees, Mastermind gives you the flexibility to specify displays where the number of widgets, the kinds of widgets, and their arrangement in the widget tree is actually determined while the application is executing. This flexibility is needed when an application needs to display variable amounts of data (e.g., data coming from a database or data created by the user interactively), when the user can resize the windows, when the user can select between different views of the data, etc.

If you had to specify the widget trees directly, you wouldn't have this flexibility because you would be specifying the widget trees before the application executes. By using presentations, you are actually specifying a set of instructions for Mastermind to construct the appropriate widget tree. Each presentation typically constructs a small portion of the display, and you have the flexibility to specify that under certain circumstances presentation A should be used for a part, while in other circumstances, presentation B should be used for a part. You also have the flexibility to specify that a part should be replicated many times, depending on how much data there is to display, or how much screen space there is to display the data. The details of how to specify these flexible presentations are discussed in the sections on replications and conditionals.

Visual Appearance

The main determiner of the visual appearance of a presentation is its prototype. If you make your presentation be an instance of MM_Button, then your presentation will look like a button. Each prototype allows you to control various aspects of its visual appearance using the following attributes of Presentation: magnitudes, colors, fill_styles, fonts, and line_styles. The guides and grids attributes also affect visual appearance, but we discuss these attributes in detail in the section on layouts.

Continuing with the database example, here is how you would specify the fonts for the labels. The MM_Label presentation has a fonts paramter called font. The font for the field-name is Helvetica bold, and the font for the field_value is Helvetica, which are represented by the object MM_Helvetica.

Record_Window : MM_Window {
  parts =
    element : Presentation {
                parts =
                  field_name : MM_Label {
                                 fonts =
                                   font : MM_Helvetica {
                                            style = Bold;
                                          };  
                               },
                  field_value : MM_Label {
                                  fonts =
                                    font : MM_Helvetica;                                
};
                                };
              };
};

As illustrated in the example, each of the attributes of Presentation used to control visual appearance is multi-valued, and you are supposed to specify the values by giving a name and a value. In our example, we specified an entry for the fonts attribute, with name font, and with value a specific font. In general, each library element documents the names that you can use when specifying values for the attributes that control visual appearance.

Connecting Displays to Application Data

Connecting displays to application data involves specifying what data is to be presented in each part of a presentation, and how the visual appearance of the presentation depends on the data to be displayed. In our example, the text of the label of the field_name part should be the name of the corresponding field in the record, and the label of the field_value part should be a text representation of the value of the corresponding field in the record.

Connections between displays and application data involve mainly two concepts from the presentation ontology: parameters and expressions. Parameters are used to specify a placeholder in the generated widgets where the application data is stored and to specify the type of the data to be displayed. Expressions are used to specify how to convert the application data into the data types of the attributes that control the visual appearance of the presentation. The conversion generally involves invoking application procedures.

In order to define the parameters and the expressions it is necessary to first specify an application model for your application.

Parameters are specified in the parameters attribute of Presentations. Here is the next version of the presentation model with parameters and expressions added. The additions to the specification are shown in boldface.

Record_Window : MM_Window {
  application_data =
    record : Parameter {
               type = DB_Record;
             };
  parts =
    element : 
      Presentation {
        primitive_data =
          name : String;
        parts =
          field_name :
            MM_Label {
              fonts = font : Helvetica { style = Bold; };
              primitive_data = text : String [Record_Window. 
parts[element].parameters[name]]];
            },
          field_value : 
            MM_Label {
              fonts = font : Helvetica;
              primitive_data = 
                text : String [as_string (
                                 record_value (
                                   Record_Window.parameters[record], 
                                   Record_Window.parts[element].parameters[name]
                              ))];
           }; 
      }; 
};

We added a parameter called record to Record_Window which is going to hold the record data to be displayed in this window. The type DB_Record is an application class defined in the application model. The value for this parameter must be supplied when the application runs.

In the element part of the presentation we defined a parameter called name. This parameter stores the name of the field to be displayed. Its value is computed by the replication statement that specifies that element is to be replicated once for each field in the record. This is explained in the section on replications.

In the field_name and field_value parts we used expressions to specify values for the text parameter that all MM_Labels have. In the MTF language, expressions are always enclosed in square brackets, and that is how they are distinguished from other modeling objects. The expression for field_name is very simple, it specifies that the value of the text is equal to the value of the parameter name defined in the element part of Record_Window (the general syntax for expressions is explained in the MTF manual.) The expression for field_value invokes the application routine called record_value passing as parameters the value of the record and name parameters specified in the enclosing presentations. The functions as_string converts the result of record_value into a string.

A subtle point with expressions is that they are evaluated when the application is executing, so they enable you to include in the model ways for calculating information at run-time. Furthermore, when any parameter changes value, the expressions that depend on those parameters are automatically re-evaluated, and the screen updated. You never need to write code to keep the displays up-to-date when data changes.

For example, if a new database record is stored in the record parameter, all the other relevant parameters will be automatically recomputed and the screen updated. The result is that the display updates to show all the information about the new record (even if it has a different set of fields).

Layout

The layout of a presentation is specified using guides and grids. To specify the position of an object it is necessary to specify the position of at least two of its guides, a vertical and a horizontal one. If the size of a presentation is adjustable, it is adjusted by specifying the position of other guides that the object might have. By default, all presentations have four guides called left, top, right and bottom. Their position can be specified by giving a value to left or right and top or bottom. Many presentations have additional guides, which can also be used to position the object, in which case the position of the left, top, right and bottom are calculated by the system. These additional guides can also be used to adjust the internal layout of the object.

If the size of an object is adjustable (e.g, a rectangle, but not a label), the size is specified by specifying values for other guides of the object. For example, it is legal to specify values for the left, top, right and bottom of a rectangle, but only two guides of a label can be specified because the size of a label depends on the label itself.

The values of guides are often specified using expressions that depend on other guides or any other parameter of a presentation or enclosing presentations. The expressions allow the specification of positions and sizes relative to other guides or relative to application data, making it possible to specify layouts that adjust gracefully when windows are resized or when the application data changes.

Here is an updated version of the database example, with guides and grids to specify the layout. The additions to the specification are shown in boldface.

Record_Window : MM_Window {
  application_data =
    record : Parameter {
               type = DB_Record;
             };
  guides =
    divider : Guide {
                direction = Vertical;
                position = Magnitude { value = 2; units = inch; };
                margin1 = Magnitude { value = 0.2; units = inch; };
                margin2 = Magnitude { value = 0.2; units = inch; };
              };  grids = 
    field_grid : Grid {
                   direction = Horizontal;
                   start = [Record_Window.top];
                   end = [Record_Window.bottom];
                   distance = Magnitude { value = 0.3; units = inch; };
                   stretchable = False;	
                 };
  parts =
    element : 
      Presentation {
        primitive_data =
          name : String;
        parts =
          field_name : MM_Label {
            fonts = font : Helvetica { style = Bold; };
            primtive_data = 
              text : String [Record_Window. 
parts[element].parameters[name]];
            guides =
              right : Guide {
                        position = [margin1 (Record_Window.divider]);
                      },
              top : Guide {
                      position = [position 
(Record_Window.parts[element].guides[top])];
                    };
            },
          field_value : MM_Label {
            fonts = font : Helvetica;
            primitive_data = 
              text : String [as_string (
                               record_value (
                                 Record_Window.parameters[record], 
                                 Record_Window.parts[element].parameters[name]
                            ))];
            guides =
              left : Guide {
                       position = [margin2 (Record_Window.divider]);
                     },
              top : Guide {
                      position = [position 
(Record_Window.parts[element].guides[top])];
                    };
          };
      };
};

We added a guide and a grid to Record_Window. The grid, called divider, divides the window vertically into two parts. The field names are displayed on the left half (right aligned to the guide) and the values will be displayed on the right half (left aligned to the guide). The guide has two small margins on each side, to provide some spacing between the field names and the values. The expressions for the right guide in field_name and the left guide in field_value specify the horizontal placement of these parts. The vertical placement is done using a grid.

The grid, called field_grid consists of a set of horizontal lines starting at the top of the window, and ending at the bottom of the window (in a more realistic example we would have used guides to divide the window horizontally into different areas, and would have placed the grid in only one of the areas). The stretchable attribute of the grid is set to false so that if the window is streched, the distance between the grid lines stays fixed, and the number of grid lines is adjusted to fill the available space. The field_grid is used to place the information about each field in the record on a separate grid space (in a more realistic application we would have defined the distance between the grid lines to be a function of the font size used for displaying the information). The expressions for the top guide of the field_name and field_value parts place these parts so that their tops are aligned with the top of the element part. We have not included expressions for defining the vertical position of the element part. This has to wait until we specify that the elements part should be replicated.

Replications

Replications are the mechanism to specify interfaces that display variable amounts of information. For our example a database record has a a set of fields to be displayed. We specified how to present one of them, and then use a replication to specify how to present all of them using that specification. When combined with the conditionals facility, the replications also allows you to specify alternative presentations for displaying the data items and the conditions under which each presentation should be used.

Replications are specified using the replications attribute of the Presentation class. A replication specification contains four key pieces of information. The replicated_part specifies which part of the presentation is to be replicated, the data_sequence specifies how to compute the sequence of data items to be displayed, the replication_index is a reference to a parameter in the replicated part , and the references specify how to lay out the multiple replicas of the part.

Here is a simplified description of the run-time behavior of a replication specification (some of the details may vary depending on the attributes of the replication specification; see the definition of the class Replication for more details). Mastermind first computes the sequence of data elements to be displayed using the expression in the data_sequence. For each element in the data sequence Mastermind creates a replica of the part (i.e., its corresponding widget) and stores the data item in the parameter specified by the replication_index. This allows each replica to access the data item that it displays. If the replication is not on_demand, then Mastermind first generates all the replicas and then puts them on a grid (if grid_reference is used), or associates them with the elements of another replication (if replication_reference is used). Replication references are an advanced feature used to place each of the elements of a replication to the right of the elements of another replication. If the replication is on_demand, then Mastermind lays out replicas as they are generated, and stops when the associated reference is exhausted (i.e., runs out of grid lines, or the reference replication runs out).

Here is an updated version of the database example, with a replication that specifies that the elements part should be replicated for each of the fields of the database record to be displayed. The additions to the specification are shown in boldface.

Record_Window : MM_Window {
  primitive_data =
    record : Data_Wrapper {
               type = DB_Record;
             },
  guides =
    divider : Guide {
                direction = Vertical;
                position = Magnitude { value = 2; units = inch; };
                margin1 = Magnitude { value = 0.2; units = inch; };
                margin2 = Magnitude { value = 0.2; units = inch; };
              };
  grids = 
    field_grid : Grid {
                   direction = Horizontal;
                   start = [Record_Window.top];
                   end = [Record_Window.bottom];
                   distance = Magnitude { value = 0.5; units = inch; };
                   stretchable = False;	
         };
  parts =
    element : 
      Presentation {
        primitive_data = name : String;
        parts =
          field_name : 
            MM_Label {
              fonts = font : Helvetica { style = Bold; };
              primtive_data = 
                text : String 
[Record_Window.parts[element].primitive_data[name]];
              guides =
                right : Guide {
                          position = [margin1 (Record_Window.guides[divider])];
                        },
                top : Guide {
                        position = [position 
(Record_Window.parts[element].guides[top])];
                      };
            },
          field_value : 
            MM_Label {
              fonts = font : Helvetica;
              primitive_data = 
                text : String [as_string (
                                 record_value (
                                   Record_Window.parameters[record], 
                                   Record_Window.parts[element].parameters[name]
                              ))];

              guides =
                left : Guide {
                         position = [margin2 (Record_Window.guides[divider])];
                       },
                top : Guide {
                        position = [position 
(Record_Window.parts[element].guides[top])];
                      };
            };
      };
  replications =
    element_replication : 
      Replication {
        replicated_part = Record_Window.parts[element];
        data_sequence = [get_field_name_list 
(Record_Window.application_data[record])];
        replication_index = 
Record_Window.parts[element].primitive_data[name];
        references = Reference {
                       grid_reference = Record_Window.grids[field_grid];
                     };
        on_demand = False;
      };
};

The replication information for our example is very simple. The replicated part is element. The sequence of data is computed by an application routine called get_field_list that takes as its only parameter the database record to be displayed and returns a list of strings that represent the field names used in that record. The replication index is the next parameter defined in the element part. This means that each replica of element has in its name parameter the name of the field to be displayed in that replica. This replication uses a grid reference, so the elements are positioned in the grid.

Conditionals

To be written for the next release of the documentation.


Masterm ind Home | Documentation Top Level