Cold on the heels of the release WidgetFactory 5.5 (well 5.6 now), I’d like to take some time to explain one of the major new features: Runtime Detection.
What is Runtime Detection? In short, Runtime Detection is the method for working out when the Captivate Movie is playing through the period of time the widget is set to appear in.
Now this is an interesting topic because there are many ways to do this, but finding one that is reliable AND CPU friendly AND can tell when you’ve moved out of the widget’s runtime period is difficult. In fact, one person described it as: ‘Taming an elusive wild jackalope.’
So before discussing the new Runtime Detection method, let’s take a look at a few alternative methods.
The isWidgetVisible() Method
If you cast your memory back to the days of early widget programing with the Adobe Widget Template (if anyone has memories of those days), a very important part of the widget everything was the ‘movieHandle’ object. This object has a method called isWidgetVisible(). isWidgetVisible() will tell you very reliably if your widget is being displayed in that special ‘runtime’ section. If you call it it will return true if you’re at runtime, and false if you’re not. For this to be useful, you have to set up an ENTER_FRAME event listener to check this method on each frame of the movie. This is true regardless of what slide the movie is currently playing through, of if the movie’s playing at all. In other words, this calculation is going on continually.
Now to it’s credit, it will detect runtime reliably, and it will also notice when the widget has moved out of runtime – but there’s a catch.
If you only have one widget in your movie, then this calculation isn’t much of a burden. But each time you add a new widget, an extra calculation is added. So if you have 10 widgets in the Captivate Movie, that’s 10 checks of isWidgetVisible() every frame. If the movie plays back at 30 frames a second, then that’s 300 checks a second. If you have 50 widgets in your movie then that’s 15,000 checks of isWidgetVisible() a second. After a while it starts to add up, slows down the movie. This is especially true on low end computers which may be used by a majority of the Captivate Movie’s audience.
Widgets are becoming more and more plentiful in Captivate Movies. Once upon a time, Captivate movies may only have had one or two widget in them. Now however, it’s not out of the range of possibility for one movie to have hundreds of widgets.
So let’s sum the method up:
- Can detect entering and exiting runtime
- The combined runtime calculations slow down the movie. So you’ve caught your jackalope, but it’s dragging its heels, and slowing you to a crawl.
From the very start, I decided this was not a viable form of runtime detection for WidgetFactory. When WidgetFactory was first released, widgets were still a new and scary feature of Captivate, and if they started to get a reputation of ‘slowing the movie down’ that could have killed them right there and then.
So I started to look for another way of detecting runtime.
The Old Method
What happens when a widget hits that special runtime period? In all honesty, not much. Widgets aren’t ‘created’ when they are displayed on the slide, they’re created right at the start of the movie. All the widget’s setup processes are handled by a different object, so it’s very difficult to find something that signals ‘runtime happening now’.
There is however, one thing that sets runtime apart from… non-runtime(?). Runtime is the only time in the Captivate movie where the widget is visible. Which means at that point Captivate must turn the widget’s visibility on.
BING! That’s different.
Now to cut a long story short, due to the ability in object oriented programming to override stuff, WidgetFactory was able to hack into the ‘visible’ switch for the widget, and call the enterRuntime() template method when the widget was turned ‘on’.
However, there was a problem with this. First of all, this only worked if the widget WAS going to be shown during this runtime period. If the visible checkbox on in the widget’s settings was turned off, then the widget wouldn’t be made visible at runtime and therefore runtime detection flat out didn’t work.
What’s more, although this method could pick up when the widget was being made visible, it did not pick up when the widget was being made invisible, because for some reason Captivate doesn’t directly turn the widget’s visibility off, but rather does so to one of its parents. So let’s break this method down again:
- No Enter Frame loop, so doesn’t leave a CPU footprint.
- Not Reliable. The jackalope’s still prancing about free.
- Can’t detect exiting runtime.
Although this method did not tax the computer’s resources, it was a bit frustrating to work with, and under certain circumstances, such as playbar scrubbing, didn’t work at all as expected.
So it was ‘okay’ but not really ‘good’. We could do better. In fact, I had an idea for a better method, but it only became achievable after WidgetFactory 5.1.
The New Method
What if we didn’t have to rely on Captivate to tell us when the widget was in runtime? What if we could work it out for ourselves? You know, be assertive and all that. Unfortunately for a long time this was not possible because we were lacking some key pieces of information. Although it wasn’t very difficult to work out which slide the widget would appear on, it was, on the other hand, very difficult to establish which frames of the slide the widget was supposed to start and end on.
I can tell you there was much searching through Captivate’s innards to try and find a place that listed it clearly. Eventually it was discovered that widgets have XML attached to them which details on how the Captivate Author set up the widget (including when they set it to appear on the timeline ). This information was made available in WidgetFactory 5.1 through the widgetInfo property. The new runtime method takes advantage of three properties of widgetInfo: startFrame, endFrame, and isDisplayedForRestOfSlide.
Here’s the idea: WidgetFactory 5.5 widgets now have a partner in crime, the Widget Manager. The Widget Manager is like a club that every widget will join. When registering with this club, the widget provides information about itself, including the startFrame, endFrame, and isDisplayedForRestOfSlide data from widgetInfo. The Widget Manager is independent. There is only one Widget Manager in a movie no matter how many widgets there are.
Keep that in mind while I talk about something completely different. Did you know there’s a real neat method in ActionScript called addFrameScript()? It allows you to link a function to a particular frame of a MovieClip. So when the flash movie is playing that Movie Clip and it hits that frame, your function will be called.
With the information available from widgetInfo, we can now tell what frames of the slide the widget starts and ends on. So the Widget Manager uses addFrameScript() to attach a function to those frames of the slide. These force each widget on the current slide to perform a check to see whether they are in runtime.
So when the Captivate movie is playing through a slide and it hits the start frame for a widget, all the widgets on the slides check themselves to see if they’re in runtime. Those that are, call their enterRuntime() method. As the movie plays along further, it will bump into the end frame for the widget, at which point, the widgets check themselves again to see if they’ve exited runtime. If so they call the exitRuntime() method.
Now this is fine assuming that the movie will always play the frames in order (1, 2, 3, 4, 5). But in practice that doesn’t always happen. Sometimes when the Captivate movies is running low on resources it will skip a frame or two (1, 2, 4, 6, 7). If the movie skipped the start frame for a widget, then the widget wouldn’t call enterRuntime() AND THE WHOLE WORLD WOULD EXPLODE!
So to get around this inconvenient combustion, the Widget Manager (and ONLY the Widget Manager) has an ENTER_FRAME loop which continually checks if there has been a frame skip. If there has, it makes every widget on the current slide check itself to see if it has entered or exited runtime. This also clears up many of the issues encountered with the audience scrubbing the playbar. You will never get two enterRuntime() calls together without an exitRuntime() call in-between them. This allows you to load and unload the widget with the enterRuntime() and exitRuntime() methods reliably. Seeing as there is only one Widget Manager in the movie, regardless of the number of widgets, the ENTER_FRAME calculations don’t accumulate. The load remains consistent and manageable.
In other words: You can catch your Jackalope and eat it too.
- Very reliable.
- Can detect runtime exit.
- A Single Enter Frame loop that doesn’t increase the load as more widgets are added.
- Plays nice with movie scrubbing.
- Works well with widgets that are displayed for rest of project.
- None that I’ve found so far.
This new Runtime Detection should give widgets a firmer ground to stand on as they continue to explore new worlds of possibilities.
Such as… Perhaps… Communication.