Articles Archive
Articles Search
Director Wiki

Smart Property Description Lists

July 27, 1999
by Chuck Neal

A while back I was reorganizing my scripts and behaviors that I had stored in libraries and realized that for some simple tasks I had as many as 5 or 6 different scripts to control each group of sprites. I started combining the functionality of a number of these, but then my getPropertyDescriptionList dialog boxes became cluttered and hard to deal with due to all the extra properties. Some of these were only used by a few pieces of the system. I started experimenting and applied some good old-fashioned Lingo to my on getPropertyDescriptionList handlers and it's now much easier to handle multiple functions in a single behavior.

Even without numerous additions, the getPropertyDescriptionList handler is a little overwhelming at first. Many beginners have a rough time figuring out the initial format, how to set ranges of values, etc., but the added functionality it gives your behaviors is well worth the effort. With a few lines of Lingo you can have a fully customizable dialog that allows user input of every variation of a behavior. This saves hours of recoding, redundant scripts, etc.

But the getPropertyDescriptionList handler is even more flexible than that. What if you wanted to have a behavior display different prompts to the user for different types of cast members? This is actually much easier than you might think. Like any Director handler, the on getPropertyDescriptionList handler accepts most any conditional statements allowing full control over what you feed it. Since the dialog box that it generates is compiled from a property list, we can custom generate this list based upon a few simple conditions.

For the purposes of this example, let's create a small system that will be used to control a field sprite and three buttons. Typically you would write two behaviours; one for the field and another for the buttons. While there is nothing inherently wrong with this approach it is much simpler to combine this system into a single behavior.

Our example behavior will control an editable text field that has 3 associated buttons.

Obviously we don't want to have the options for the button types display when we drop the behavior on the text field and, conversely, we don't want field options to display when we apply the behavior to the buttons. Using the member type property we can easily display only the appropriate options.

property fieldSprite, spriteNum, function
property startState, clearStart, theType
on getPropertyDescriptionList me
 p_list = [:]
 thisType =  sprite(the currentSpriteNum).member.type 
  if thisType = #field then
    addProp p_list, #startState, [#format : #boolean, ¬
      #default : true, #comment : "Start with the field unlocked?"]
    addProp p_list, #clearStart, [#format : #boolean, ¬
      #default : true, #comment : "Clear the field at startup?"]  
  else if thisType = #button then
    addProp p_list, #function, [#format : #symbol, #default : ¬
      #clear, #comment : "This button is to :", #range : ¬
      [#clear, #lock, #unlock]]
    -- Director will fire a getPropertyDescriptionList event so 
    -- we need to add this so we don't get the error every time 
    -- we recompile. Thanks John!
    if NOT symbolP(thisType) then
      alert "this behavior only works with fields and buttons"
    end if
  end if
  return p_list

This script looks at what type of sprite the behavior is dropped on and displays the appropriate options for the user.

Notice that the property list we will return is declared before the conditional statement. This avoids having a void variable being returned as the property description list. As well, this allows for any variables we may want assigned to all of the objects to be initially declared. Once this is done we can then use the conditional statements to check the cast member's type and then display only the properties it needs.

Once the property list has been declared we just check the type of member in the beginSprite handler and determine what setup (if any) the behavior needs to do to the sprite it is attached to. Again we create some conditional code based on the sprite's member's type.

In this case

on beginSprite me
  -- check the type of the sprite and act accordingly
  theType = sprite(spriteNum).member.type
  if theType = #field then
    -- for a field sprite we need to set the editable 
    sprite(spriteNum).editable = startState
    -- and possibly clear the field's contents
    if clearStart = true then
      sprite(spriteNum).member.text = ""
    end if
    -- now tell all the button sprites 
    -- which channel we are in
    sendAllSprites(#storeFieldSprite, spriteNum)     
    -- its a button as we tested for this earlier
    -- get the current member 
    thisMember = sprite (me.spriteNum).member
    -- change the name of the button to 
    -- reflect its functions
    case function of
        thisMember.text = "Clear"
        thisMember.text = "Lock"
        thisMember.text = "Unlock" 
    end case
  end if 

on storeFieldSprite me, whatSprite
  -- store the sprite ref that the field sent to us
  fieldSprite = sprite(whatSprite)

The storeFieldSprite handler simply records the field's spriteNum when it "broadcasts" it. This is a simple way to transmit data when you don't know the sprite numbers of the sprites that will need the data. In general though you should be aware of the performance penalties that using sendAllSprites will create.

The only thing that remains is to get the behavior to react to the user. As before, we use the same type of conditional statements to differentiate between the different elements in the system. When the user clicks on the field sprite we don't want to do anything. But when the user clicks on one of the three buttons we want it to react accordingly.

on mouseUp me
  if theType = #field then
    -- don't do anything for a field
  else if theType = #button then
    -- its a button so test for its type
    case function of
        fieldSprite.member.text = ""
        fieldSprite.member.editable = false
        fieldSprite.member.editable = true  
    end case
  end if

This technique gets more useful every time I use it. It has taken my "out-of-control" behavior libraries and made them into nice neat pieces that are far easier to organize. You also remove the risk of misplacing one piece of the system you forgot to copy. I found this to be especially valuable when creating the behavior library on my site as I didn't have to cross-link 3 or 4 behaviors together. I used it in all of my ActiveX control behaviors as well, so the end user just needs to drop the script on everything, and doesn't need to know where everything goes, how the ActiveX works, etc.

There are a number of ways to further enhance this technique. Conditional statements can not only be based on the type of a member but also on names, the cast a behavior is in, the current behavior list, color, etc. Throw a few conditions into your getPropertyDescriptionList handlers and see what it can do for you.

A sample movie, in Mac or PC format, is available for download

Chuck Neal is CEO of MediaMacros, Inc. and owner and operator of He has worked on projects for clients such as Coca-Cola, United Parcel Service, Ford Motor Company, the US Marine Corps, BBC, Sony, DreamWorks Records, Hasbro Toys, Saatchi and Saatchi, as well as many commercial products and games. Chuck has spoken at Macromedia’s Developers conferences, been a guest speaker at a number of Macromedia User Group Meetings, taught Director training classes, written for numerous online and print publications such as Computer Arts and MX Developer’s Journal, and is well known in the Forums for offering regular advice as a member of Macromedia’s volunteer program “Team Macromedia”. Chuck currently accepts contract work on full projects for delivery on CD, web, games, kiosks and installations, as well as support services for firms of all size.

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