Chapter 4. Support Code

Table of Contents

4.1. The Application class
4.2. The LinearXform class

This code is included in the DataHub distribution to facilitate writing scripts for the DataHub.

4.1. The Application class

This is the parent class for all the applications you create with the New button in the Scripting option of the Properties window. It provides an environment that among other things, makes it easy for you to program for changes—a primary benefit of DataHub scripting. What follows is a quick overview of the Application.g file where the class and its methods are defined.

/* A base application class that keeps track of change functions
   and removes them when the object is destroyed */

if (undefined_p(Application) || !class_p(Application))
{
    class Application
    {
        _ChangeFunctions;
    static:
        _Instances;
    }
}

This defines our base class. The instance variable _ChangeFunctions is a list of all the change functions that are defined by the class's .OnChange method. The class variable _Instances is a list of all the instances of the class that have been created. The undefined_p and class_p functions in the if statement are Gamma predicates that test data types.

The reason for the if clause is to avoid re-creating the class. If the class definition were re-executed in a subsequent load, then the _Instances class variable would be different for each time the class is redefined. This would be fine for the destructor, but since we want to use the _Instances variable to track the currently loaded applications, we do not want several different copies of it floating about.

method Application.constructor ()
{
    ._Instances = cons (self, ._Instances);
}

Here each instance of the class gets added to the list of all the instances of the class. The Gamma cons function is used to build the list.

method Application.destructor ()
{
    ._Instances = remove (self, ._Instances);
    with x in ._ChangeFunctions do
        remove_change (car(x), cdr(x));
}

When an instance of the class gets destroyed, this .destructor method will be run first. It removes this instance from the _Instances list using the Gamma remove function. Then it it applies the remove_change function to every member of the _ChangeFunctions list. The Gamma with statement is used to cycle through the list. The car and cdr functions access the necessary elements in the list.

method Application.OnChange (sym, fn)
{
    local        chfn = cons (sym, fn);
    ._ChangeFunctions = cons (chfn, ._ChangeFunctions);
    on_change (sym, fn);
    chfn;
}

This method is a wrapper for the on_change function that builds the _ChangeFunctions list as it goes. First it creates a two member list consisting of a symbol (sym) and the function that should run (fn) that should run when the symbol changes value. That short list is added to the _ChangeFunctions list. The Gamma function cons is used for building the lists. Finally, the symbol is linked to the function by the on_change function. What gets returned, chfn, is a two member list—exactly what the unwrapped on_change would have returned.

method Application.RemoveChange (chfn)
{
    ._ChangeFunctions = remove (chfn, ._ChangeFunctions);
    remove_change (car(chfn), cdr(chfn));
}

This is a wrapper on remove_change, to be used when you need to remove just a single function from _ChangeFunctions rather than all of them.