Chapter 5 Example ADL Programs

5.1 Toggle Button Class

In this example, we develop an ADL class that provides a user interface button that changes its label when pressed. Each label corresponds to a different value for some variable, thereby allowing any ADL program using the button to set other variables or take some action that depends on the new value. Since the toggle button has most of the characteristics of a regular XFbutton object, it is natural for the ToggleButton class to inherit from XFbutton.

A typical situation where such a button is useful is a case where we need a button to set a value with two mutually exclusive options. For example, we want to have a button that when pressed sets a value that is used to determine if video will be played with or without subtitles. The button has two possible labels: "Show Subtitles" and "Hide Subtitles". Each time the user presses the button the label changes from one value to the other, and the value stored by the button shifts from TRUE to FALSE.

You can configure the button so that you can set the number and contents of possible labels when the button is created. To do this, the ToggleButton class has two members that are lists. The first, called labelList, is a list of character strings corresponding to the set of labels the button may display. The second list, called valueList, holds the corresponding values.

The integer member currentPosition stores the number of the currently displayed list element. Each time the user presses the button, the value of currentPosition changes. In addition, a member called buttonValue holds the currently active value for the button. Because the values can be of any type (list, integer, handle, etc.), the member of buttonValue is of the ADL type any.

We also provide the toggle button with default labels "Yes" and "No", with corresponding values of TRUE and FALSE. The defaults are set up so that the initial label is the string "Yes" and the initial value of the button is TRUE. You can override these defaults when using the ToggleButton class.

5.1.1 ADL Implementation of the ToggleButton Class

Here is the ADL code for the ToggleButton class, with detailed comments.
ToggleButton Class
class ToggleButton: XFbutton

{

list labelList = {'Yes, 'No};

integer currentPosition = 1;

Nro {'Create, 'Pressed, self, 'Toggle, NULL} => toggleNro ;

list valueList = {TRUE,FALSE};

any buttonValue;

upon Create: handle hparent

init {{'Create, hparent} => XFbutton}

{ }

on Init

{

label = at(currentPosition, labelList);

buttonValue = at(currentPosition, valueList);

{'Subscribe, &toggleNro} => self;

}

on ChangeValue: any newValue

{

any temp;

integer counter=1;

for temp in valueList {

if(getType(newValue) == getType(temp) && newValue == temp) {

buttonValue = temp;

label = at(counter, labelList);

currentPosition = counter;

return;

}

counter = counter+1;

}

}

on Toggle: any cd, list keys, list vals

{

currentPosition = currentPosition+1;

if(currentPosition > length(labelList)) {

currentPosition = 1;

}

label = at(currentPosition, labelList);

buttonValue = at(currentPosition, valueList);

}

}; /* end of class ToggleButton */

Line 1 declares the class named ToggleButton and indicates that this class derives from the XFbutton class.

Line 3 declares the member labelList to be of type list and initializes its value to a list of two strings, "Yes" and "No". These strings are the default labels for the button unless the programmer using the class changes them.

Line 4 declares the integer member currentPosition and initializes its value to 1. This indicates that by default the first string in the list labelList is the initial label for an instance of a ToggleButton.

Line 5 declares an NRO (notification request object) named toggleNro. As with all NROs, the Nro class has a special constructor called Create that has four arguments:

a string giving the name of the activity (in this case Pressed)

a handle giving the target of the notification required (in this case handle self indicates that the message is to be sent to ToggleButton)

a string giving the name of the method to be messaged when the activity occurs (in this case a method named Toggle)

arbitrary client data (in this case the handle value NULL)

Line 6 declares the member valueList to be of type list and initializes its value to a list of two booleans, TRUE and FALSE. These are the default values associated with the labels "Yes" and "No" for the button, unless the programmer using the class changes them.

Line 7 declares the member buttonValue to be of type any. This member stores the current value associated with the ToggleButton.The values stored in buttonValue will be entries from the list valueList. The use of the ADL data type any allows users of the ToggleButton class to replace the default valueList with a list containing any valid data type.

Line 9 begins the special constructor method named Create. This method is provided so that a user of the ToggleButton class can use the new operator to create instances of the class ToggleButton on the heap. In ADL, any object that is drawn on the screen and is created dynamically at run time needs a special constructor so that it can pass a handle to the parent of the new widget. This is done through the method argument hparent. Note that we do not need a special constructor for the case where we declare a static instance of a ToggleButton because the standard, default constructor Construct provided by AM2 is adequate for the task.

Line 10 is a base class initialization statement, indicated by the keyword init. This statement ensures that when we create an instance of a ToggleButton using the new operator, the instance of the class from which ToggleButton derives is correctly initialized. In this case, the ADL statement

{'Create, hparent} => XFbutton

ensures that the Create special constructor for the base XFbutton class is called rather than the default Construct method. Any user interface widget or subclass of such a widget created from the heap using the new operator must have its parent widget explicitly set. The default Construct method does this automatically for statically created widgets.

Line 11 is an empty body for the Create method. There are no additional initializations that we need to perform here.

Line 13 is the start of an Init method. This method automatically receives a message whenever an object of this class is constructed. This message is sent after all the other steps in the creation of an object, i.e. after the Construct message is sent (or when some other special constructor is used), after the initialization block, (also called an izor) is executed, and after any asset declarations are applied. The body of the Init method is used to set initial values and to subscribe to the Pressed activity for the button.

Line 15 sets the initial value of the label for the button to a value on the labelList. The initial label is set to the currentPosition-th element of the labelList. This allows the ADL programmer using the ToggleButton class to set the currentPosition member in an izor block, thereby changing the initial value of the label.

Line 16 sets the initial value of the member buttonValue. It uses the built-in function at() to extract a value from the list valueList.

Line 17 sends the Subscribe message to the button, registering the NRO named toggleNro. This results in the message Toggle being sent to any member of the ToggleButton class whenever the user presses the button.

Line 18 closes the Init method.

Lines 20-21 start a method called ChangeValue. We use this method to reset the value of the ToggleButton to some new value. It provides the ADL programmer with a way to alter the label and corresponding value of the ToggleButton after it is created. This feature gives the programmer a way of changing the label without requiring the application's user to actually press the button. The ChangeValue method uses a single argument of type any because the ToggleButton class allows the elements of the valueList to be of any valid ADL type, including compound types such as a list.

Line 22 declares temp to be a local variable of type any.

Line 23 declares an integer variable named counter and sets its initial value to 1.

Line 24 begins a loop over all the values in the valueList.

Line 25 tests if the value of the argument newValue equals one of the values in valueList. Note that this comparison is done by first testing if the value in temp is the same as the value being checked on the list, and then by checking if the two values are equal. This is necessary because the equality operator (==) cannot be used on values of different types. Even though both of the variables being compared are declared of type any, the values they hold have definite ADL types which may not be the same.

Lines 26-29 execute when the value requested is found in valueList. This group of statements sets the variable buttonValue, changes the label of the button to the corresponding value in labelList, sets the currentPosition member appropriately, and returns.

Line 29 updates the value of counter each time the loop over the elements in valueList is executed.

Lines 32-33 close the loop and the method definition respectively.

Lines 35 is the start of the declaration of the method Toggle. This method is called every time the ToggleButton is pressed.

Lines 37-40 begin by incrementing the value of the currentPosition by 1. If the revised value of currentPosition is greater than the number of elements in the labelList (computed by applying the built-in ADL function length() to labelList), then the currentPosition is reset to 1. This code has the effect of moving through the labelList and wrapping around to the start of the list when the last value on the list is reached.

Line 41 updates the value of the button label.

Line 42 updates the value of the variable buttonValue to correspond to the label now being displayed.

Line 43 closes the Toggle method.

Line 44 ends the declaration of the ToggleButton class.

5.1.2 An Example of Using the ToggleButton Class

Given the example shown above, we now turn to a simple ADL program that actually uses the ToggleButton class. Suppose that we want to have a button on an application that sets the background color for the main application shell widget. We might have a button that toggles among several different colors. Each time the user presses the button, the background color of the XFtop in which the application is running changes. In our example, we allow the user to set the possible background colors to white, black, red, blue and green.

The ADL program shown here implements this idea.

ToggleButton Example
anonymous : XFtop {

ToggleButton myButton {x=50; y=50; height=50; width=150;

recomputeSize=FALSE;

labelList={'White,'Black,'Red,'Blue,'Green};

valueList={'white, 'black,'red, 'blue, 'green};};

upon Construct

{

background = myButton.buttonValue;

myButton.Pressed = {'ShiftBackgroundColor, self};

}

on ShiftBackgroundColor

{

background = myButton.buttonValue;

}

} myTop {height=400; width=400;};

Line 1 starts the definition of an anonymous instance (used when one or a very few instances of the class are needed) of an object that inherits from the ADL top level shell class, XFtop.

Lines 2-5 declare a member of this anonymous class that is an instance of a ToggleButton named myButton. The button has a list of labels and values set in an izor block that correspond to the colors we want to use as options.

Lines 7 - 8 start the Construct method for the anonymous class. Since this is a constructor, it begins with the upon keyword. This method is automatically invoked when the object is created.

Line 9 sets the initial background color of the widget to the value stored in the buttonValue member of the ToggleButton.

Line 10 sets the value of the Pressed attribute of myButton (corresponding to the Pressed activity of the button) to a list that gives the name of the method to be invoked when myButton is pressed, and the target of the method. In this case, the method ShiftBackgroundColor of the anonymous instance that is the shell widget (as indicated by the special handle self, automatically defined for every ADL instance) is messaged when the button is pressed. Note that this could also be done by declaring an appropriate constructed notification request object and then subscribing that object to myButton. We discuss this further in the next subsection below.

Lines 13-16 define the method ShiftBackgroundColor. This method resets the background color of the shell to the current value stored in myButton.

Line 18 closes the definition of the anonymous subclass of the standard shell widget. It gives the widget the name myTop and uses an izor block to set the widget's width and height.

5.1.3 Implementation Options

One of the interesting aspects of button widgets that the toggle button example illustrates is the use of notification request objects (NROs) and the Pressed attribute of a button. In the ADL code for the class ToggleButton, we intentionally use an NRO to register for the Pressed activity, while in the ADL program that uses the ToggleButton class we set the Pressed attribute. It is reasonable to ask why we did not use the Pressed attribute in defining the ToggleButton class.

The answer to this question requires a clear understanding of the Pressed attribute. Basically, setting the Pressed attribute is a shortcut that has the effect of subscribing an implicit NRO to a button's Pressed activity. However, this way of setting an activity handler has two limitations: only one method can be registered in this way, and the method must not require any arguments be passed when the activity is triggered. If the Pressed attribute of a button is set more than once, only the last setting takes effect. All earlier settings are lost.

Thus, if we set the Pressed attribute in the class definition for ToggleButton rather than subscribing to the activity using an explicit NRO, we force users of the ToggleButton class to not use the Pressed attribute, but rather subscribe an NRO instead. If the users of the ToggleButton class erroneously reset the Pressed attribute, the ToggleButton will no longer work correctly. This makes the ToggleButton class far less useful and leads to hard-to-diagnose errors when the class is used incorrectly.

The implementation of ToggleButton could be improved in several ways. First, we have not included any error checking to make sure that the number of items in valueList is equal to the number of items in labelList. We could rewrite the Construct method so that if the lists provided by the user are of different lengths, the longer of the lists is truncated so that they the lists actually used by the ToggleButton have the same length.

Another improvement would be to make some of the values in the ToggleButton "read only" from any ADL statement outside the scope of the object class. In ADL, this is done by defining a "Set_" method for such variables. For example, it makes sense that the member buttonValue should never be set outside of the class; only the class methods Init, ChangeValue and Toggle should be able to alter this member. To do this, we could add the following method to the ToggleButton class:
ToggleButton Set_buttonValue Example
on Set_buttonValue: any val

{ }

This method turns any assignment statement outside the ToggleButton class with the member valueButton on the left hand side into a null operation.

5.1.1 - ADL Implementation of the ToggleButton Class
5.1.2 - An Example of Using the ToggleButton Class
5.1.3 - Implementation Options

AM2 Documentation - 19 NOV 1996

Generated with Harlequin WebMaker