Editor's Note: The author is the developer of Windows for Shockwave (WFS),
a collection of scripts and media assets that can be used to create various types
of interface elements. WFS 3.0 is a commercial product that costs US$29.99. Because
there is no method for distributing protected Lingo scripts, no download is included
in this article, but I felt that it was an interesting tool that may solve issues
for some Director developers which was worthy of exposure to DOUG's audience. -Darrel Plant,Editor]
This is an overview of Windows For Shockwave 3.0 (WFS 3.0), which is a set
of behaviors for Director 8+ (not an Xtra) that enables drag and drop creation
of on-Stage windows, modal dialog boxes, cascading menus, right-click (Control+click
in Mac) pop-up menus, other multi-sprites, and good cursor image control. It can
be used in the creation of Shockwave movies or Projectors. The drag and drop behaviors
are suitable for Director developers with no Lingo knowledge. WFS also supplies
an extensive API for programmers to access more advanced functionality.
The WFS library as it appears in the
Library Palette.
In authoring tools/languages such as C++, Delphi, Visual Basic, etc, there
is no Score (timeline) and development proceeds window-by-window or menu-by-menu.
The resulting applications are, conceptually, one-frame movies in which objects
are dynamically created and destroyed. WFS 3.0 aims at giving Director developers
the ability to create high-performance online applications window-by-window or
menu-by-menu.
Multi-Sprites
WFS supports what are called multi-sprites in the WFS documentation.
A multi-sprite is a collection of visual sprites that behave as a single entity
in certain ways. The overarching abstraction in WFS is not really the notion of
the window or menu, but the multi-sprite. The product began with the idea of just
developing windows for Shockwave, however (hence the name).
When you want to build an entity that consists of several
sprites that behave as a single entity, you are into
multi-sprites. Multi-sprites are very flexible in their
look and functionality.
A window is an example of a multi-sprite. So is a menu.
A window has a background and various other sprites
in it. Same with a dialog box. A menu is basically a
window that is closed by clicking away from it.
From tutorial 5 of the WFS documentation.
Illustrated: menus, windows (modal and non-modal), rollovers, parent-child relationships,
& cursor control.
A menu system is a collection of windows between
which there are parent-child relationships. The main
menu is the root menu. Submenus of the main menu are
child windows of the main menu (the parent window).
Submenus of submenus are child windows of their parent
submenu.
But a multi-sprite could as well be a creature with
independently moving limbs. Or perhaps the creature's
limbs each form a multi-sprite, and the body is 'glued
together' via parent-child relationships between the
multi-sprite limbs and torso, etc. Multi-sprites are
collections of individual sprites flexibly 'glued together'
in certain ways. Parent-child relationships between
multi-sprites coordinate the behavior of collections
(or families) of multi-sprites. Parent-child relationships
are how you 'nest' multi-sprites.
WFS
Implementation
How are multi-sprites implemented in Director? The basic idea is that a multi-sprite
is managed by a manager sprite. A multi-sprite's manager script contains handlers
to do things such as make the multi-sprite visible or invisible, move it around,
move its family of multi-sprites around, center it on Stage or otherwise align
it, and dynamically change its parent-child relationships.
The window manager sprite member is a 1x1 black bitmap named 2:
Window Manager. This humble bitmap is important to the implementation
of modal dialog boxes and menus. A modal dialog box is a type of window. An example
is the File>Save
As modal dialog box you encounter in applications. You must close the
dialog box before you can access the rest of the application. The way this is
done in WFS is that the manager bitmap is stretched across the entire Stage, below
the modal window in locZ
order, at a configurable level of transparency, and the attached 3:
Window Manager script has mouse handlers that absorb the mouse events.
This is also how it is possible to close WFS menus by clicking away from them.
A menu system is like a modal dialog box in this regard.
So managers are more or less invisible most of the time but play a crucial
role in the 'glue' that holds multi-sprites together.
The way windows and menus and other multi-sprites look on the Stage is up to
you (though WFS comes with many sample DIR files you can use). The way they appear
in the Score is a bit more prescribed by WFS. Normally, a multi-sprite appears
as a block of sprites in the Score, as shown below:
From tutorial 1 of the WFS documentation.
Illustrated: A window is normally a rectangular block
of sprites in the Score.
In the above figure, we see the Score and the Stage.
The window's manager (sprite 1) is invisible on the
Stage; and it is above the window elements in the Score.
A multi-sprite normally looks like a rectangular block
of sprites in the Score.
This sort of rectangular appearance in the Score is not absolutely necessary,
however. What is necessary is that the manager be above the elements
in the Score, and that the manager be instantiated when the elements become instantiated.
Because when an element is instantiated, its beginsprite
handler assumes its manager is the nearest manager in the Score above itself in
the Score.
How
to Use WFS
Creating
a Window Manager
To create a Window Manager, you drag and drop a copy of the 1x1 pixel 2:
Window Manager bitmap into the Score. Then you drop a copy of the 3:
Window Manager behavior on it. The following Parameter Dialog Box opens:
Window
Manager Parameter Dialog Box
As you see above, you can configure windows so that
they are initially visible (or not), and are brought
to front when clicked (or not).
The slider in the above graphic determines whether
the window is modal or not and, additionally, determines
the amount of opacity of what's behind the window when
it's open. To see modal and non modal windows, play
with the .DCR for tutorial 5.
You can also configure windows so that they have a parent (or not) and specify
whether the window is moved when the parent is moved. You can see how parent-child
relationships work in the piece below:
From
tutorial 2 of the WFS documentation.
Illustrated: Parent-child relationships, opening and closing windows.
As you can see, when you drag
window 1, window 2 and window 3 behave as though they
are nested in window 1. Parent-child relationships are
how nesting of multi-sprites is supported in WFS. When
a window is closed, its open descendant windows are
also closed. And children stay in front of parents.
Note that the above piece also illustrates how WFS allows you to configure
where windows are opened. When you use the 7:
Open A Window behavior, you specify whether you want the window opened
at an absolute location, or whether you want the window centered, or opened where
the mouse is, or not moved but simply opened.
On beginSprite, managers
add themselves to a global variable gWindowList
maintained in the 1:
prepareMovie movie script. gWindowList
contains the names and spriteNums
of all multi-sprite managers, be they windows or menus. Managers delete their
entries from this property list on endSprite.
Creating
Window Elements
It doesn't matter where window elements are located on the Stage, but where
they are located in the Score is important. Elements, on beginSprite,
look for and assume that their manager is the nearest, higher manager sprite in
the Score; this is why elements must always be below their manager in the Score.
It is also why managers must be instantiated when elements become instantiated.
This is a kind of general notion involved in the construction
of manager sprites of all sorts: the manager is higher
in the score than the worker sprites and the worker
sprites, as soon as they're born at run-time, dutifully
go and find their boss. Depressing, I know, but it works.
You don't get too many sprite revolts.
You assemble your window in the Score and on the Stage. Then you drop the 4:
Window/Menu Element behavior on the sprites that make up the window
(except the manager).
An element of a multi-sprite is a sprite that has the 4:
Window/Menu Element behavior attached to it. If it doesn't have this
behavior attached to it, a sprite will not behave like an element. This behavior,
on beginSprite, finds its
own manager sprite and informs its manager that the manager has a new element
to manage.
The manager thus maintains a list of the spriteNums
of its elements, and elements maintain the name and
spriteNum of their manager.
Elements delete themselves from their manager's list
of elements via the endSprite handler in the 4:
Window/Menu Element behavior. Elements are born and die as the manager remains instantiated.
But once the manager dies, an element is without a manager
and won't be able to do much WFS work unless the addElementToManager
handler is used to assign it a new manager. So it's
usually best to just have elements die before or at
the same time the manager dies unless you get handy
with the addElementToManager handler and have special
needs.
Creating
Menus
There are different types of menus. In desktop applications,
you normally close a menu by clicking away from it or
by making a menu selection. The former is not normally
true in web menus. Web menus normally close on mouseLeave
or by making a menu selection. WFS supports the desktop
application type of menu, not Web menus. Desktop application
menus also normally close when you press the Esc key
and you normally can navigate menus with the keyboard,
as in Alt+F for the File menu, and so on. But WFS does
not support keyboard shortcuts. Director developers
often have more pressing needs concerning keyboard event
handling; I didn't want to burn any CPU cycles on menu
shortcuts. You could program that in if you wanted,
however.
How you create a menu in WFS is very similar to how
you create a window. A menu, like a window, has a manager
and each menu item has the 4: Window/Menu Element
behavior attached to it.
To create a menu, you drag a copy of the Menu
Manager bitmap into the Score. Then you drop a
copy of the Menu Manager script onto the bitmap sprite. The
Menu Manager Parameter Dialog Box then opens
and looks like this:
Menu
Manager Parameter Dialog Box
You are prompted to specify whether this menu manager
is the root of the menu system. The root is the main
menu. Each menu system has one root manager. An application
can have multiple menu systems, but each menu system
has one root.
You can also specify the parent. Roots can have no
parent or a window as parent. In the latter case, the
menu system will move when the parent window is moved.
Submenus must have a menu parent.
Then you assemble the menu on the Stage and drop the
4: Window/Menu Element behavior on all the
elements of the menu (except the manager, as usual).
Each menu item has the Menu Verb behavior
attached to it. When you drop the Menu Verb
behavior on a menu item, the following Parameter Dialog
Box opens:
Menu
Verb Parameter Dialog Box
The Menu Verb parameters allow you to specify
whether you want a menu or window or nothing opened
(which is useful for menu items which open browser windows)
and, if you want something opened, where you want it
opened. The options are
"Don't want one opened."
"Do not move it, just open it."
"Center it."
"Open it where mouse is."
"Absolute location."
You can also specify whether you want the menu item
highlighted on mouseEnter, and whether the menu system
should close when the user selects the menu item and,
if so, on what mouse event.
Menu systems in WFS can look normal, as in tutorial
5, or can be unconventional in appearance, as in
the example below:
From tutorial 3 of the WFS documentation.
Illustrated: Menus can be unconventional in appearance.
WFS menus are primarily intended as menus for Director
applications and, more specifically, for Shockwave works,
since Director menus are unsupported for Shockwave but
are supported for projectors. However, I have used WFS
menus as menus for HTML+Shockwave projects, as in Paris
Connection or as in the WFS
HTML documentation. I made this choice in these
projects because I wanted a fairly deluxe menu system
graphically, and the Javascript menu systems I came
across were inconsistent in their cross-browser, cross-platform
support. The disadvantage of WFS menus for HTML projects
is that they occupy a fixed rectangular space, whereas
Javascript menus layer over` the HTML.
WFS also supports cascading pop-up menus, as shown
in the piece below. The piece below is a simple example,
but if you learn how to make the sort of menus shown
in tutorial 5 and tutorial
3, you get the idea; they are all the same type
of menus.
From
tutorial 4 of the WFS documentation.
Illustrated: Pop-up menus are supported.
Other
WFS Behaviors
WFS comes with a variety of behaviors, as you can see
from the graphic of the WFS library.
For instance, there's the 7: Open A Window
behavior. This behavior allows a sprite to act as a
button to open a WFS window or menu. When you drop this
behavior on a sprite, you are prompted for the name
of the window or menu you want to open, and prompted
also for other information such as where you want the
window/menu opened and also for what mouse event you
want to trigger the opening of the window. The mouse
events you can select include rightMouseUp.
There are also drag and drop behaviors to close windows/menus/multi-sprites.
The 6: Handle behavior is one you drop
on an element in order to be able to drag around a window/menu
(or family thereof). When windows in the tutorial
.DCR files are draggable, it's via this behavior.
The Rollover behavior opens a window on
mouseEnter of some sprite, and closes the window on
mouseLeave. You can see this in tutorial
5 via menu1>menu1,2>rollover1.
WFS also includes a nicely configurable Cursor
Control behavior. This allows you to select from
all Director's built-in cursors for different mouse
events. Notice that it is kinda smart when you do tricky
things with the mouse.
The 1: prepareMovie movie script initializes the
globals in the project and contains handlers that manage
those globals. All WFS projects must contain a copy
of the 1: prepareMovie script in a Cast.
WFS
in Your Applications
In my work, generally all sprites are part of some
window or menu. This is not necessary, but I've found
that it saves me time since they usually end up needing
to be part of a window/menu as the project expands
and any particular scene comes to need multiple windows
visible simultaneously, and as parts of scenes
need to be made invisible, opened, centered or moved
around, etc. Most sprites in Arteroids,
which uses WFS 2.0, are in some window. WFS 2.0 did
not support menus, so the menus in Arteroids are a bit
flaky. The menus in Arteroids are just windows.
This gets back to the idea of building an application
window-by-window and/or menu-by-menu. But Arteroids
is not a one-frame movie. Different independent scenes
are separated in the Score. But there are occasions
when Arteroids requires multiple open windows simultaneously.
Particularly when menus and their dialog boxes are involved.
Windows are also handy when the player resizes the browser
window: in that case, windows are easily re-aligned
on the resized Stage.
Another reason to have most every sprite be part of
a window or menu is WFS creates and manages a locZ space.
When you open a window or menu, WFS brings the window
or menu to the front of the locZ space. It is very unlikely
that, if a sprite is not an element of a window or menu,
it will protrude inappropriately into the locZ space
because the locZ space is initialized to start at the
spriteNum of the last channel. When a window is
opened via a call to openWindow, a call is made to
boostHighestLocZ which boosts gHighestLocZ by 2500,
so that the newly opened window is 2500 locZ units above
anything else on the stage: guaranteed to be above
any other window or menu element. Why such a large boost
in locZ? Well, you want some room to play with because
you can dynamically add and delete elements from windows.
Can all that boosting of gHighestLocZ result in an overflow
value? No, it can't. That is managed also.
So making sprites part of some window or menu makes
them part of the locZ space. It isn't absolutely necessary
and you are almost sure not to run into problems if
you don't make a sprite part of the locZ space, but
obviously when you are dealing with simultaneously instantiated
windows composed of multi-sprites you have to manage
locZ values, and WFS does this quite well. Take advantage
of it.
Pros
and Cons
Performance
This HTML page has five .DCR files in it running WFS.
Yet they all run quickly. This is an indication of the
high performance of WFS. There is only one WFS behavior
that does any constant processing:: the 6: Handle
behavior is used to drag multi-sprites around as a unit;
and it only does one comparison per frame when it is
not actively dragging a multi-sprite around.
Nor does WFS take up much memory. The 1: prepareMovie
script, which each WFS project must contain, adds 2kb
to a .DCR. The 2: Window Manager bitmap
and the 3: Window Manager script, together,
add 6kb to a .DCR, and you only need one of each of
these regardless of how many windows your movie contains.
Adding an additional window manager to the Score adds
less than 100 bytes to a .DCR. And the 3: Window
Manager script, along with the equally long Menu
Manager script, are the biggest scripts in the
WFS library. Adding the 4: Window/Menu Element
behavior adds 1.7kb to a .DCR and, again, you only need
one copy regardless of how many window elements you
have.
WFS is not an Xtra. The online viewer does not need
to download and install any Xtras to run WFS.
WFS
Compared with MIAW
All WFS windows and other multi-sprites are on a single
Stage. MIAW (Movies In A Window) windows
are on separate Stages. MIAW supports parent child relationships
much like WFS does. But MIAW is unsupported in Shockwave.
MIAW only works in Authoring and Projector run modes.
If you want different Stages for windows in Shockwave
pieces, they must be in different browser windows. They
must be separate .DCR files. But then there are considerable
problems getting windows to talk with one another easily
and quickly, because of cross-browser, cross-platform
Javascript issues. WFS is a solution for windowed
Shockwave work.
MIAW requires Lingo scripting whereas non-programmers
can use the WFS drag and drop behaviors more easily.
Some people therefore use WFS as a replacement for MIAW.
But MIAW has features that WFS does not.
WFS
Compared with Flash SWF Imports
It is wise to use Flash and Director together, often.
You can import Flash SWF into Director and they can
communicate with Lingo scripts. Flash is excellent for
creating vector-based animations. Director does not
compare well with Flash, in this regard, though Director's
abilities to create bitmap manipulations outstrips Flash.
However, Actionscript is typically 30-60 times slower
than Lingo. So it is wise to have imported SWF do little
computation.
Even when you import SWF into Director, when they are
on-Stage, they are usually in the company of other sprites,
be these Flash imports or sprites with Director-created
members. WFS is for turning such a collection of sprites
into a window that can be made invisible, moved around
as a single window, and so on.
WFS and Flash imports serve different purposes in
Director.
WFS
Compared with LDMs
Rob
Romanek and James
Newton have written articles on LDMs that are well
worth consulting. Jakob Hede Madsen, an experienced
LDMer, has said:
"My experience is that once you have
removed the kinks, LDMs work reliably. Just be prepared
to spend so much time removing those kinks that you
ask yourself if you made the right decision. So plan
accordingly."
LDMs have issues that require special attention. And
there is, as yet, no package available that takes the
kinks out for you.
WFS is a system that is easy to use. It gives you features
that would take a substantial investment of time to
develop using LDMs.
Additionally, WFS allows you to dynamically add/delete
individual sprites of any type between WFS multi-sprites
via the addElementToManager handler. This would be like
deleting an element of an LDM and adding it, dynamically,
to a different LDM. LDM does not support it natively.
One would have to write code to support it. The WFS
feature is illustrated below:
From tutorial 6 of the WFS documentation.
Illustrated: addElementToManager and spriteIsWithin handlers.
LDM does have certain advantages over multi-sprites
in some situations. For instance, it would be difficult
to support scrolling windows in WFS without the ability
to crop arbitrary member types, which is unsupported
in Director. This becomes apparent when you ask what
happens to sprites when they scroll toward and off the
edge of the window: they become either partially or
wholly invisible. It's the 'partially visible' part
that requires cropping. Alternatively, it requires scrolling
so that it's impossible to make a sprite need
to be partially visible--which is doable but depends
on the sizes of the sprites in the windows, if you see
what I mean (if you don't, never mind). Possibly
some sort of convoluted masking scheme would do the
trick, but it's doubtful, and even if it worked, it
would probably be slow. Here we see an advantage of
the LDM container wall.
Additionally, it would be hard, though not impossible,
to support resizable windows in WFS because when you
resize a window, different elements are handled in slightly
different ways. For instance, some elements will not
be moved or resized, whereas the window background is
resized; and the 'close window' button typically at
top right of a window is not resized but is moved. One
would have to develop a behavior that you drop on all
window elements, and this behavior would have to be
wisely configurable to handle all possible ways elements
behave when a window is resized. Not impossible but
I haven't written it yet.
Another difference between WFS and LDM is that there
is no native support in LDM for dynamic parent-child
relationships, though you can (staticly) nest LDMs.
You would have to write the code to support dynamic
parent-child relationships concerning an LDM system.
WFS provides the setParent, setChild and deleteChild
handlers to dynamically adjust parent-child relationships
between multi-sprites and their descendants.
Also, if you wanted modal LDM windows, you would have
to write the support for it yourself. WFS supports modal
windows.
Programming
APIs
Although WFS contains drag and drop behaviors that
allow non-programmers to create multi-sprites, it also
contains a well-documented API for Lingo programmers
to work beyond the drag and drop behaviors.
1:
prepareMovie API (for programmers)
The 1: prepareMovie movie script contains
the following handlers:
These handlers allow you to check a window name or
manager spriteNum to see if the manager is instantiated,
get the manager spriteNum of a window with a particular
name, and so on. gWindowList is one of the primary variables
in the project; it maintains a property list of the
instantiated windows and menus.
Normally you would not have to use these handlers except
if you were doing customization of WFS.
gHighestLocZ is an integer that represents the highest
locZ of any sprite that is a window or menu element.
You can see that in dealing with multi-sprites, it is
important to assign locZ intelligently. WFS manages
this for you concerning windows/menus and their elements.
gOpenWindowList is, as you might guess, a subset of
the entries in gWindowList, namely those windows that
are currently open.
Normally you would not have to use these handlers unless you are a Lingo programmer doing customization of
WFS.
API
to detect intersection and containment
spriteIsWithin
spriteIntersects
These two handlers are handy for detecting when a sprite
intersects with or is contained by a window. spriteIsWithin
is used in tutorial 6 of the WFS
documentation.
These handlers allow you to move and align elements,
multi-sprites and families thereof. For instance, moveTheFamilyBy
moves a multi-sprite and all descendent multi-sprites
(configured to be moved when the parent moves) by a
number of pixels horizontally and vertically. How far
you want them moved is of course specifiable. These
handlers are used by various WFS behaviors.
These handlers allow you to dynamically alter the parent-child
relationships between multi-sprites. The setParent handler
is called in the beginSprite handler of window
and menu managers.
Miscellaneous
getIAmVisible
The API for the Menu Manager behavior is
almost identical to the 3: Window Manager
API. The only difference is that menus are opened and
closed in slightly different ways.
4:
Window/Menu Element API (for programmers)
addElementToManager
changeRegPointToTopLeft
The addElementToManager handler is illustrated in tutorial
6. changeRegPointToTopLeft is used by WFS on
the background sprite of a window. The background sprite
of a window is, by WFS convention, the element below
the manager. WFS changes the regpoint of background
window sprites so that it can move windows around consistently.
The
Rest
Debugging
When you use the WFS behaviors improperly in authoring
mode, you will get an error message from WFS. The error
message will usually tell you how to fix the problem.
This contributes to ease of use.
Documentation
WFS comes with extensive documentation. The Lingo code
itself is extensively documented. The HTML documentation
includes a document on each behavior detailing its usage
and public handlers, if it has any. All the .DIR
files for all the examples in this article are included
with WFS, along with HTML tutorials for each of the
.DIR files. Additionally, there is usually an 'unfinished'
and a 'finished' version of the tutorial .DIR files
so that you can work through the tutorials from start
to finish and compare the results with a 'finished'
version of the tutorial .DIR.
Support
There is a Windows for Shockwave email list for support.
It isn't very busy because the documentation is good.
Please consult the documentation first. But the list
is there if you get stuck; I get the messages and respond;
I want people to succeed with WFS.
The email list will also hopefully develop into a forum
for the development of further behaviors that use WFS
and extend it. Part of the reason why the code itself
is so well-documented is because I want it to be readable
by developers, extendable and customizable by developers,
so that WFS evolves, via community, into its full poetential.
Windows
for Shockwave 4.0
Windows for Shockwave 4.0 (anticipated release date:
August 2003) will support dynamic creation/destruction
of multi-sprites and will also support dynamic attachment/detachment
of WFS behaviors. I chose to support this sort of dynamism
because in my own work, the projects are fairly large,
the Score is deep, and I don't want Scores that are
too deep. My projects almost invariably involve situations
where the number of on-Stage sprites depends on the
user's actions, typically when they construct something
or do battle with a variable number of thingys or whatever.
I would prefer to allocate such channels during run-time
rather than authoring time. WFS 4.0 will allow you to
instantiate multi-sprites on the fly and destroy them
on the fly rather than having to allocate all resources
in authoring mode and guess how many channels you might
need.
This guessing game can end up limiting the number of
channels you have available for a particular resource
(if other resources are taking up channels that aren't
being used), and maximizing the number of simultaneously
instantiated sprites. The limit, in Director MX, is
1000 simultaneously instantiated sprites. One wants
to be well below that, however, for performance reasons.
Dynamic sprite creation/destruction becomes more or
less a necessity as one moves into big high-performance,
multiple-window projects.
WFS 4.0 will also make standard menu creation less
work and will also reduce the number of sprites and
behaviors involved in creating a standard menu. Unconventional-looking
menus will still be supported, however.
I mentioned at the beginning of the article that in
authoring tools/languages such as C++, Delphi, Visual
Basic, etc, there is no Score (timeline) and development
proceeds basically window-by-window, or menu-by-menu.
The resulting applications are, conceptually, one-frame
movies in which objects are dynamically created and
destroyed. WFS 3.0 supports the "window-by-window"
and/or "menu-by-menu" part of the above. WFS
4.0 will support the "dynamically created and destroyed"
part.
Jim Andrews has been using Director since 1999 when he started making
interactive audio Shockwave pieces. He started development of WFS three years ago while making windows and menus for Arteroids. He is currently employed at the University of Victoria as a Director programmer of interactive audio with musicians and programmers across Canada.