Articles Archive
Articles Search
Director Wiki
 

Behavior Initializers

January 4, 2001
by Brennan Young

Behaviors are the most powerful and simple way to involve object-oriented design in Director projects. Director 6, and the studio versions of Director 7 and 8, shipped with libraries of great behaviors to handle some of the most everyday authoring tasks. Most of these behaviors make extensive use of behavior initializers, commonly experienced by end users as the behavior parameter dialog box, which appears when the behavior is first attached to a sprite.

For all their power and ubiquity, behavior initializers are underdocumented by Macromedia, and incompletely understood by many Director users. This article is an attempt to gather all my knowledge on the subject of behavior initializers, and to present it such that Lingo scripters can approach behavior design with a more thorough understanding.

Something that strikes me about this topic is that the nomenclature seems to be in flux. The blue diamond icon button in the Behavior Inspector (two interlocking gear wheels in Director 8) reveals the tooltip Parameters, and indeed this is the name used in the Director documentation and help. However, the Lingo most intimately connected with the process uses various other names, such as getPropertyDescriptionList, runPropertyDialog, getBehaviorInitializers and the scriptList of sprite. Let's look at this Lingo in detail and try to better understand the relationship between these things.

The runPropertyDialog and getPropertyDescriptionList handlers are very special handlers that can be added to behaviors while authoring. What makes them most special is that they are called by Director during authortime, and that they return values to the system. There are a couple of other places where a value or control is explicitly returned to the system: in particular, the pass control statement, when used with editable texts and fields; and the value returned by the on alertHook handler.

Three other handlers are also called at authortime, if they exist: isOKtoAttach; getBehaviorDescription; and getBehaviorTooltip. These all contribute to the documentation of the behavior. The first of these has been discussed in another DOUG article by Gary Rosenzweig, and the latter two are discussed briefly below.

The runPropertyDialog and getPropertyDescriptionList handlers behave in similar ways, at least if they are written correctly: both of them return a property list describing the parameters assigned for a particular behavior to a particular sprite. Without knowing about the underlying implementation, it's clear that this data is stored in the sprite, rather than in the behavior. Sprites therefore have a property that has been accessible to Lingo only since version 8, and otherwise can only be modified with the GUI. I will be focusing on these details in the next article in this series.

When you drag a configurable behavior onto a sprite, the parameter dialog or property dialog appears and allows you to change the parameters manually. (I'd prefer to call this the "parameter dialog" because the word property is used a great deal in Director). The parameter dialog represents an interface to the behavior's properties that are public or exported to the scriptless author. The way the parameter dialog appears is marked up by the return value of the getPropertyDescriptionList handler. Here's an example:

property destination, transition

on mouseUp me

  puppetTransition transition
  go destination

end

on getPropertyDescriptionList me

  set pdlist = [:]

  addprop pdlist, #destination, [#comment:"Jump to which marker?", #format:#marker, #default:the frameLabel]
  addprop pdlist, #transition, [#comment:"Transition type", #format:#transition, #default:1]

  return pdlist

end

It doesn't matter exactly how you construct the return value, as long as it ends up with a valid structure. This leads me into potentially dangerous coding style territory: many scripters like to code the whole thing into one line, making liberal use of the continuation character and whitespace characters; while I prefer to devote one addProp statement to each property, the better to add/remove and otherwise edit the thing when necessary. I just think it's less typographically fragile that way. An even more flexible approach would be to construct the inner property lists with addProp, but this makes the handler very long.

The example above would return the following structure to Director (formatted with whitespace for clarity):

[
  #destination:
    [
      #comment:"Jump to which marker?",
      #format:#marker,
      #default:"xyz"
    ], 
  #transition,
    [
      #comment:"Transition type",
      #format:#transition,
      #default:1
    ]
]

The list returned by getPropertyDescriptionList must be a property list; and to be useful, each item in the property list should have a property name that corresponds to one of the behavior properties.

In the behavior example above, the behavior has a destination property and a transition property so that the parameter dialog is of use. Notice that these properties are declared at the top of the behavior, and used in the mouseUp handler.

Note that you may include properties in the Property Description List that are not matched by any declared properties in the behavior itself. Such properties can still be accessed inside the behavior by using the propertyName of me or me.propertyName, in much the same way that the implicitly defined spritenum property is accessible even when it is not declared. I can think of no good reason why you would want to do this, but it's important to be aware of the possibility because you might do it by accident. Here is an example behavior using this technique, for the sake of completeness:

on mouseUp me
  go me.destination
end

on getPropertyDescriptionList me

  set pdlist = [:]

  addprop pdlist, #destination, [#comment:"Jump to which marker?", #format:#marker, #default:the frameLabel]

  return pdlist

end

In this example, the property destination is not declared, but is nonetheless defined by the getPropertyDescriptionList handler, and accessed using the syntax me.destination.

Deeper into the Property Description List

The value of each item in the Property Description List must also be a property list, and must have the following three properties specified; #comment, #format and #default. These are now described in turn:

#comment

This is a string expression that will appear on the left of the parameter dialog box, instructing the "scriptless author" what the property is or does. It is designed to be read by a human being, rather than a computer, so you should certainly be descriptive. I'd like to suggest that you be as verbose as you like. Unfortunately, human interface guidelines and screen real estate issues dictate that you must be concise and brief in your comments. (See the caveats about window boundaries below.) Inserting &return& will not help much, because the comment for the next parameter will always appear on the very next line no matter what. If you do insert return characters, the extra lines will be drawn behind the parameters that follow. You'll have to try this out to see what I mean. Maybe someone can find a use for this.

Remember that the value of the comment need not be fixed. You can create a string dynamically so that the comment changes as your movie grows. It's difficult to think of a useful example, but it's interesting to keep this fact in mind.

#format

This is a symbol expression that can be chosen from the list below. Your choice will affect what kind of UI widget appears beside it, although the optional #range property will affect this too. See below for more information about #range.

Format GUI Widget Evaluated as
#integer Field #integer
#float Field #float
#string Field #string
#symbol Field #symbol
#member Popup list of cast member references #member1
#bitmap Popup list of bitmap cast member references #member1
#filmloop Popup list of filmloop cast member references #member1
#field Popup list of field cast member references #member1
#palette Popup list of Director's standard palettes and palette cast member references #string or #member1
#picture Popup list of PICT cast member references #member1
#sound Popup list of sound cast member references #member1
#button Popup list of button cast member references
(Director 6 button members only).
#member1
#shape Popup list of shape cast member references #member1
#movie Popup list of movie (LDM) cast member references #member1
#boolean Checkbox #boolean 
#script Popup list of script cast member references #member1
#richtext Popup list of richtext cast member references
(Use #text in Director 7 or later).
#member1
#ole Popup list of ole cast member references #member1
#transition Popup list of transition cast member references
and transition types
#integer or #member1
#digitalvideo Popup list of digital video cast member references
(Not QuicktimeMedia in Director 6.5 or later)
#member1
#xtra Field ?
#frame Field #integer
#marker Popup list of markers (frame labels) plus "next", "previous" and "loop" #string or #symbol
#ink Popup list of inks #integer
#cursor Popup list of named system cursors. (Not cursor cast members) #integer
#graphic Popup list of graphic (i.e. visual) cast member references #member1
#vectorShape Popup list of vector shape cast member references.
(Director 7 or later).
#member1
#text Popup list of text cast member references #member1
#font Popup list of font cast member references.
(Director 7 or later).
#member1
#swa Popup list of shockwave audio cast member references #member1
#quicktimeMedia Popup list of Quicktime cast member references. (Director 6.5 or later) #member1
#animgif Popup list of animated gif cast member references.(Director 7 or later). #member1
#font Popup list of embedded font cast member references. (Director 7 or later). #member1
#list Field #list 2
#proplist Field #proplist 2
#point Field #point 2
#rect Field #rect 2
#color Field (Color picker in Director 8 property inspector) #color 2
     
  1. There is a gotcha in Director 6 when using named Cast members in parameter dialogs. See below.
  2. There is a gotcha when you mess up entry of these non-primitive datatypes. See below.

Evaluation and Coercion of Data Entered into a Parameter Dialog

If, in a field widget, you enter an expression of the wrong type, such as an integer into a field whose format is #float, it will be coerced or cast to the type specified. In some cases, such as the coercion from string to integer, this will not be possible and runtime logic errors may occur; but the failure to coerce the inputted value to the appropriate type will not in itself cause an error message. In the case of those formats that generate popup list widgets where no suitable member of the specified type exists in any cast, the popup list will be replaced by a field. The popup lists of Cast member references will display the name of the cast member, if it has one; otherwise, the Cast member will be referred to in the form member m of castlib c.

Cast Member Names Gotcha in Director 6

There is a quirk in Director 6 and 6.5: if the scriptless author selects a named Cast member from the popup list, the setting will be stored as a string (the Cast member name) rather than as an explicit member reference. If you have several Cast members with the same name, this may cause problems, as Director will always take the first Cast member whose name matches. This is a particularly difficult bug to track down, as anyone who has experienced it will tell you, so watch out.

In Director 7 and later, named Cast members are stored in behavior initializers as bona fide member references, so you shouldn't have this problem. Even so, it's asking for trouble to give more than one Cast member the same name; so to reduce debugging time, just don't do it.

Runtime Evaluation of Behavior Parameters

One of the most powerful possibilities is to provide a string or field format and then, either on beginsprite, or regularly at runtime (e.g. in an exitFrame handler) evaluate the string or field using Lingo's do or value() functions. For example, you could enter the string "random(256)" in the parameter dialog box, which of course will evaluate to an integer. This will not be fast, but it affords massive flexibility.

If you choose an editable field which is actually on the stage, you can even have the end user editing behavior properties at runtime!

Here's an example behavior that uses runtime evaluation of a string entered into the parameter dialog box. The sprite with this behavior will move toward the point denoted by the expression entered into the dialog box. If that point changes, the sprite updates its target point. The default string is "the mouseLoc", but of course, you could enter something like "sprite(3).loc", or any expression (no matter how complex) that evaluates to a point.

property spritenum
property dpString
property destinationPoint
property steps
property step
property oneStep

on beginsprite me

  destinationPoint = value(dpString)
  delta = destinationPoint - sprite(spritenum).loc
  oneStep = delta / steps
  step = 1

end


on prepareFrame me

  p = value(dpString) -- runtime evaluation

  if p <> destinationPoint then -- destination point has changed!
    
    destinationPoint = p
    delta = destinationPoint - sprite(spritenum).loc
    oneStep = delta / steps
    step = 1
    
  else
    
    if step <= steps then
      step = step + 1
      sprite(spritenum).loc = sprite(spritenum).loc + oneStep
    end if
    
  end if
end


on getPropertyDescriptionList me

  set pdlist to [:]

  addprop pdlist, #dpString, [#comment:"Destination Point", #format:#string, #default:"the mouseLoc"]
  addprop pdlist, #steps, [#comment:"Steps to get there", #format:#integer, #default:10]

  return pdlist

end

This is not a high-performance way of working, as you will see if you try it out, but it is very flexible. Of course, you could have the expression evaluated less often - for example, only in a mouse event handler, or only once in the beginSprite handler - and achieve excellent performance that way. This requires two properties, one containing the string to evaluate, and the other containing the evaluated value.

Using High-Level Lingo Datatypes

It is undocumented but obvious that, just as #integer and #string are natural choices for the #format of a parameter dialog item, you can also use non-primitive datatypes as the format, such as #point, #rect, #list, #proplist and #color. The latter is particularly interesting in Director 8's Property Inspector, because it appears as a color picker chip widget.

In other cases in the D8 property inspector, and in every case in the parameter dialog box proper, the widget that appears for these types will normally be a field where you can type the value in directly.

However, there's a gotcha here: Director will get confused if your syntax is incorrect when you type into a field formatted for a high-level Lingo datatype (for example, if the #format is specified as #list and you enter [1 2 3] instead of the syntactically correct [1, 2, 3]), and the property will be stored as a string. If you then go back and correct the data so that it includes the necessary commas, Director will continue to store the list as a string, even though it is now syntactically correct, so you may need to detach and reattach the behavior to get the data to be seen properly.

Raw Datatypes

Even though uses may be limited to guru developers only, it's also possible to use #image, #instance, #object, #window, #media or #picture as a format specifier. In this case, you had better make sure that you provide a #range of such datatypes as a popup list, because if you don't, you will be presented with a field into which you can not type anything useful. For this kind of reference to be useful, you will have to use #string as the format, and then evaluate it at runtime as described above.

#default

A default value is presented to the scriptless author the first time she opens the parameter dialog box. This serves at least two purposes. One is that some time can be saved if the value is a common, or recommended choice. Another is that it gives her a further hint about the kind (i.e. datatype) of information that should be specified, and what sort of sensible range is expected (see #range below for more information about this). Many scriptless authors have problems with abstract ideas, and it's informative when, for example, a speed parameter is presented with a default value of 2, so that she knows she should not really be writing 5356 in there. It gives a ballpark figure.

The default value need not be of the same type as described by the #format property. In any case, a type conversion will usually take place so that the format is satisfied. If the format is such that a popup list is presented to the user (such as #member or #marker), then the default value can be anything. Commonly, I use zero in this case to save on typing. This does not mean that the #default setting can be left out, just that it is not critical: if you, for example, have #bitmap as the format, but do not have any bitmap members in your cast yet, you can just use a dummy value as the default. In this case, a field widget will appear instead of a popup list. When you eventually do get some bitmap members in your cast, Director will do the right thing, and present a popup list.

Many behavior authors have taken full advantage of the #default property, adding several lines at the beginning of the getPropertyDescriptionList handler to intelligently offer a recommended default. Commonly, this would be the current cast member or its neighbor in the cast. Chuck Neal even recommended offering wholly different sets of parameters to the scriptless author, according to the type of the Cast member used by the sprite, or even other contingencies.

In object-oriented theory, this is known as polymorphism and is a fascinating subject with many implementations. Alas, such polymorphous behaviors often become difficult to maintain, given that they have so many forks. If there were some way to create classes inside classes (as is possible with Java and AppleScript for example), this would not be a problem.

Many correspondents on DIRECT-L and Lingo-L have recommended that we keep our behaviors as short and simple as possible - that it is better to have dozens of simple behaviors that do specialist tasks than to have a handful of more complicated polymorphous ones. I must say that when I create behaviors for students, I'm more inclined towards the polymorphous kind, simply because all users are different, and it's important to be able to cater for different mindsets and approaches. It's also fascinating to see exactly what range of features you can pack into a behavior, and how much authoring power you can pack into the property dialog box, although in principle I respect simplicity rather more.

For my own use in professional products, I will commonly make the simpler kind.

Optional Settings for the Property Description List

#comment, #format and #default are obligatory, and you will get an error message if you leave one out. There are a couple of optional settings you can add to further customise yourcustomize parameter dialogs:

#range

This can be used to provide a set of options to the user as a popup list, or a horizontal slider for a numerical range.

For a popup list, the value for #range must be a linear list, where each item represents an entry in the list. Here is an example:

on getPropertyDescriptionList me

  set pdlist = [:]

  set stooges = ["Curly", "Larry", "Moe"]
  addprop pdlist, #stooge, [#comment:"Slap which stooge?", #format:#string, #default:"Larry", #range:stooges]

  return pdlist

end

This will produce the following parameter dialog:

Interestingly, strings are case sensitive in this context. If you change the default to larry instead of Larry, the default value of the popup list will, er, default to the first item in the range. This will occur in any situation where there is an inconsistency between the default value and the range. If you don't want (or can't be bothered) to enter the default value, just use 0 or any dummy value and it will take the first item in the range instead.

Nested lists might be imagined to produce submenus. They don't. They create large integer error codes instead.

Mac-only Minus Divider Bug/Feature

One more undocumented feature on the Mac platform (a bug in some cases) is that you can add horizontal dividers to these popup lists, by including minus/hyphen characters in the range list:

on getPropertyDescriptionList me

  set pdlist = [:]

  set governingForces = ["Predestiny", "-", "Freewill"]
  addprop pdlist, #force, [#comment:"Entire life dictated by...", #format:#string, #default:"", #range:governingForces]

  return pdlist

end

This will produce the following parameter dialog:

Notice the default value given here is the empty string, so it is the first item in the range list, which is selected by default. On Windows, the minus/hyphen is not treated as a divider, so you might want to fork the code there for Mac users so that they can feel more cosy, and so that Windows users don't need to be reminded about how clunky their GUI is. (Please include "platform wars" in the subject line of your flame feedback on this matter.)

To be serious, if you are using a Mac, this dividing line created by a minus character can be problematic in those situations when you actually want to include the minus character, or a negative number in the range:

on getPropertyDescriptionList me

  set pdlist = [:]

  set directions = [-1, 1]
  addprop pdlist, #direction, [#comment:"Direction", #format:#integer, #default:-1, #range:directions]

  return pdlist

end

This will produce the following parameter dialog:

Notice that the -1 is missing! This is because -1 begins with a minus character, which is taken to be a horizontal divider. To solve this problem, you have to include negative numbers in the range list as strings with a space in front, and to rely on the coercion of the selected value to the correct type (in this case, an integer). If you want to include a string that starts with a hyphen, you can do the same trick. If it starts with a space, or some other dummy character, it will not be interpreted as a divider. It strikes me as bad form on Macromedia's part that this "gotcha" is undocumented, but given that this is at least partly Apple's fault, we might forgive them.

Slider Controls

The other possible use for the #range property is to create a horizontal numerical slider. Clearly, this is only appropriate for #integer and #float formats, and the widget will be overridden by any other formats.

To create a slider, the #range should be given as a property list with at least two values, labeled #max and #min.

Here is an example:

on getPropertyDescriptionList me

  set pdlist = [:]

  set blendRange = [#min:0, #max:100]
  addprop pdlist, #maxBlend, [#comment:"Maximum Blend", #format:#integer, #default:75, #range:blendRange]

  return pdlist

end

This will produce the following parameter dialog:

There are no problems with negative numbers, but the value of the slider must not exceed four characters, including a minus character, or it will not be displayed correctly:

on getPropertyDescriptionList me

  set pdlist = [:]

  set m = [#min:-9999, #max:9999]
  addprop pdlist, #maximum, [#comment:"maximum", #format:#integer, #default:-9999, #range:m]

  return pdlist

end

This will produce the following parameter dialog:

Notice the last 9 of -9999 has been truncated! In fact, you can use the slider to set values that exceed these, but you will be working blind because the slider will not display the extra digits. In a related gotcha, float sliders will display more characters (nearly seven, including the minus sign) but can not exceed the mystery absolute values of 168.6, as demonstrated by the following:

on getPropertyDescriptionList me

  set pdlist = [:]

  set m = [#min:-9999.0, #max:9999.0]
  addprop pdlist, #maximum, [#comment:"maximum", #format:#float, #default:-9999.0, #range:m]

  return pdlist

end

I have not tested whether abs(168.6) is the maximum float for a slider on all implementations, and would be interested to hear if it differs on yours.

Configuring the Increment Buttons on a Numerical Slider

You can expand the configuration of a range value like this:

[#min:0.0, #max:1000.0, #increment:1.0, #jump:10.0, #acceleration:0.5]

These extra properties have their effect when you press the little increment buttons instead of dragging the slider. They affect how much and how fast the slider value increases and decreases. Once again, the float precision of the display seems to be locked at 2, and I can't get any finer resolution in the slider display than 0.05, even though finer values can be set in this way. Examine the Behavior Inspector or Property Inspector after messing around with this and you will see the finer tuned values there. Setting the floatPrecision has no impact on this, so if you want your slider to have a finer resolution and see what you're doing when you are manipulating the slider, you'll need to scale the property elsewhere, such as in the beginsprite handler. Director 8's Property Inspector is a little more flexible, offering sliders and a number entry field.

Limits on Parameter Dialog Box Size

You have little control over the actual layout of the property dialog. If you allow it to be too big (comments too long, or too many parameters), you will be treated to the following error message:

This is one of those rare Director error messages that looks like it was written by one of the engineers, rather than an in-house HCI specialist. (I do appreciate seeing the man behind the curtain from time to time.) I'm pretty sure it's from MUI, with which many (all?) of the Director dialog boxes are made.

I haven't thoroughly researched this on both platforms, but it would appear that people running Director at lower resolution or on smaller monitors are at an increased risk of seeing this error which, on other video setups, occurs much more rarely. There is, therefore, no absolutely safe upper limit for the the size of the parameter dialog, and remember that its size is dynamically calculated according to all the settings. You should probably try to get it to fit inside 640 x 480, especially if you plan to distribute your behaviors to other people. Ideally, we would have the option of choosing the font size for the text used in the parameter dialog, so that we could construct elaborate airplane cockpits of settings for power users.

This concludes my discussion of the nuts and bolts of the property description list. It is quite a labyrinth, but a very important one, which presents fascinating challenges to the creativity of the programmer. I'd love to see the functionality expanded to allow, for example, dynamic disabling and enabling of widgets, more control of layout and formatting, tooltips, radio buttons and all the other things we expect from a traditional GUI.

Remember that we all have some power in influencing such developments by sending brief emails off to the Director Wishlist - which, Macromedia assures us, is not just a mail dump.

Brennan Young is an English freelance multimedia designer / programmer living and working in Copenhagen, Denmark. He started making interactive presentations on Commodore and Acorn computers as a teenager in the early 1980s, but went on to study Fine Art and Art history at Goldsmith's College, London where he discovered Director. He teaches and lectures on multimedia at various institutions around Denmark. When he is not fiddling with interesting authoring software, he composes and performs music, writes theoretical and practical articles, and 'makes art' for exhibitions or private consumption.

Copyright 1997-2024, Director Online. Article content copyright by respective authors.