New Runtime Detection Explained

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.

YouAreHere

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:

Pros

  • Reliable
  • Can detect entering and exiting runtime

Cons

  • 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. Sad smile

SNAG_Program-0020

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:

Pros:

  • No Enter Frame loop, so doesn’t leave a CPU footprint.

Cons

  • 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 Open-mouthed smile). 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.

Let’s review:

Pros:

  • 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.

Cons:

  • None that I’ve found so far.

Conclusion

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.

Posted in Theory, Widgets | Tagged , | 4 Comments

A Word on Partial Scoring

So Rod had been on to me for a long time to look into partial scoring. Which is basically a way of conveying ”You sorta got it right, but not entirely” as a quiz score. Currently all Captivate Quiz Questions and Interactive Objects can only report two scores: Zero and whatever number you gave it other than zero.

This static score is a bit limiting, and many people out there, who are extending the bounds of what Captivate can do, have been trying to find ways around it. Until recently the only viable method was employing Javascript. Which, for the non-programmatically minded, is – uh – Javascript.

So we wanted to find a way to open up the world of partial scoring to the grand populous. After a little more Captivate spelunking we found a way to BEND CAPTIVATE TO OUR WILL! MUAHAHA! The rest, as they say, is the Infosemantics Interactive Master Widget Version 1.1!

Don’t believe me? Take a look at this video here:

Pretty cool right?

And before you ask, yes this will be in the next version of WidgetFactory. Definitely for Interactive Widgets, most likely for Question Widgets too. WidgetFactory 5.6 shouldn’t be too far away and you can harness the awesome power of partial scoring for your very own widgets!

Bonn appetite!

(And yes I know I haven’t blogged about the features in WidgetFactory 5.5 yet. STILL GETTING AROUND TO IT!)

Posted in Interactive Widgets, Question Widgets, Widgets | Tagged , , , , | 5 Comments

An Introduction to the Infosemantics Master Widget

I’m afraid I haven’t had time to put up another blog post for a while now, because I’ve been too busy doing this!

Here we are, two videos for the Infosemantics Interactive Master Widget (or ‘Master Widget’ for much shorter).

The first one has me, in the flesh, introducing the concepts behind the Master Widget:

The next one has me, less in the flesh, showing how to use the Master Widget to create an interaction with our Drag and Drop Interactive Widget (double publicity!).

Please leave a comment bellow if you have any questions about the Master widget.

Also I’d like to say that if you have an Interactive Widget publicly available which is not built with WidgetFactory, feel free to flick me an e-mail and I’ll let you know how to get it to work with the Master Widget.

Happy slave driving!

Posted in eSeminars, Interactive Widgets, Widgets | Tagged , , , , | 2 Comments

WidgetFactory 5.5.1 and Question Pools

Just a quick post to let you know that I released a minor update to WidgetFactory which fixes some problems with widgets in question pools. Click here to get the update.

While I’m here I may as well talk about what I’ve learnt about question pools.

Whatfore art thou Question Pools?

From the Captivate author’s standpoint, question pools are a group that they can assign certain quiz questions to. These questions are kept separate from the rest of the lesson and left to their own devices would never appear in the movie. However, when a ‘Random Question Slide’ is added to the movie, it will pick a random question, from the pool of your choice, to display in the movie. This way the audience will get different quiz questions for each time they watch the lesson.

Here is what’s going on behind the scenes to make this happen:

When the Captivate Movie is opened all the question pool slides are created and then stored in a sort of waiting room which is separate from other slides in the movie. Random question slides however, are created and placed where the Captivate Author set them to appear in the movie. When the movie enters a random question slide, it goes searching in the waiting room for a question pool slide to display. When it finds one, the random question slide makes itself the parent of the chosen slide. So the random question slide is not replaced by the question pool slide, it becomes the parent of the question pool slide. The question pool slide is inside the random question slide. You have a slide inside a slide.

QuestionPoolStructure

When the audience moves to the next random question slide, it will then go to the waiting room and pick its question pool slide.

So here are a few things to remember:

  1. Random question slides are slides in their own right. Not just placeholders for the quiz slide.
  2. The decision on which question pool slide will appear in the movie is not made until just before the audience enters it.
  3. Question pool slides are not counted with the other slides in the movie. So they don’t have a slide number assigned to them.
  4. Random question slides however, do have a slide number assigned to them.
  5. If you had a widget on another slide of the movie which is trying to access slide elements on the question pool slide with getSlideObjectByName(), then it won’t work. Because getSlideObjectByName() will be searching for the slide elements in the random question slide, not the question pool slide.

So what does this topsy turvy system mean if you’re building a widget which might be used on a question pool slide?

Widgets and Question Pools

Perhaps the most significant difference is that the enterMovie() template method is not called at the start of the movie after the widget has set itself up. This is because the question pool slides are in the waiting room at the start of the movie and therefore outside the typical Captivate Movie structure. At this time WidgetFactory is unable to locate the elements it needs to set up the widget (like slides and the Captivate Main Timeline). So the widget delays its setup until the question pool slide is added as a child to the random question slide. The slide is now part of the typical Captivate Movie structure and the widget can find the elements it needs to set itself up, after doing that the enterMovie() Template Method will be called.

This delay in enterMovie() can cause some troubles if your widget is trying to join a widget room. I haven’t written an article on these yet, but when I do I will explain that it’s usually best behaviour for your widget to join rooms at the start of the movie. In other words: In the enterMovie() template method.

Now I’m afraid it’s not all good news and clean shoes. Although widgets now co-exist with question pools in Captivate 5 and Captivate 5.5, in Captivate 4 they are still at odds. Actually, they don’t work full stop. From the tests I’ve done, I can tell you that the movie doesn’t even get to the point of creating the widget before experiencing a terminal cardiac arrest. There is some error inside Captivate that prevents the widget being created and therefore the problem can’t be fixed in WidgetFactory. The good news is that the bug has already been fixed! So if you’re getting complaints from a user, tell them to upgrade to Captivate 5/5.5.

I hope that makes the pool a little clearer for your guys. Time to dive in!

Posted in Captivate Movie Structure, Question Widgets, WidgetFactory Builds | Tagged , , , , , | Leave a comment

WidgetFactory 5.5

It’s been a long time coming, and now it’s here…

5 POINT 5 YEEEEEHAAAA!

That’s not to say that WidgetFactory 5.1 wasn’t compatible with Captivate 5.5, but… Yeah.

WidgetFactory 5.5 has many new features, but there are three major ones. I will briefly describe them here, and then in the coming weeks write a post that goes into greater detail for each of them.

Just before I delve in here, I’d like to say that anyone out there who has an Interactive Widget should update to 5.5 as soon as possible. Why? All I can say is… Stay tuned :)

Debugging

Debugging has always been difficult with widgets, because the only true way to test them is to pull them in to Captivate and see how they fare. When a swf leaves the confines of its design environment a lot of its debugging features leave as well.

WidgetFactory 5.5 now has an interface to trace to external debuggers. This interface is focused on delivering the best debug experience for widgets.

If you need information on how to use these features before I write the next article, see the documentation under the WidgetDebugger class.

Communication

Widgets have come a long way since they were released, they are moving past childhood and into the awkward stages of adolescence. Probably no other milestone will be more awkward, or powerful, than communication with other widgets. But do not worry, because WidgetFactory 5.5 is here to ease the awkwardness.

Just a note up front, the communication architecture in 5.5 is not the only way that widgets can communicate with each other. In fact there are many ways that communication can be done. The hope is this architecture will help to establish a standard which will allow different types of widgets (even those created by separate developers) to communicate with each other.

Here’s the concept: There is a ‘room’ and widgets can become ‘members’ of the room. By joining the room, widgets can contact each other and make decisions that take into account all other members of the room. Alternatively, the room itself could become a middle man for its members, it receives requests from widgets and decides which should be acted upon.

WidgetFactory 5.5 provides two types of rooms:

  • Global Rooms: Are available for all widgets to register with, no matter where they are in the movie. (See the BaseRoom class in the documentation)
  • Slide Rooms: Are only open to widgets on a certain slide. (See the BaseSlideRoom class in the documentation)

When your widget creates a room it has to decide what type of object the room will be. A room could be created with the BaseRoom or BaseSlideRoom classes listed above, or a class of your own creation that extends either BaseRoom or BaseSlideRoom.

Anyway, more information on this to come. Until then, the third major feature is…

Runtime Detection

Runtime detection is how a widget detects the Captivate Movie is playing through the time period the widget is supposed to appear. Now this doesn’t sound like such a big deal, but believe me, it is.

The problem is not so much finding a way to detect runtime, but finding a way that doesn’t chew up CPU. It’s a balancing act of accuracy and resources, and with WidgetFactory 5.5 we’ve found that balance. I’ll tell you more about the method in another post. :)

When a widget ‘detects runtime’ it will call the enterRuntime() template method. We’ve all used that one right? (<– I knew this was a mistake the instant I typed it. But I kept it in and wrote this aside instead. Go figure). One thing that always bothered me about the ‘enterRuntime()’ template method was that it had no ’exitRuntime()’ method to balance it out. Well guess what… now there is!

enterRuntime() is called when the Captivate Movie enters the period of time that the widget is set to appear, and exitRuntime() is called when the movie exits that period. This will make things like loading and unloading the widget much easier. In my projects now I find myself using exitRuntime() just as much as enterRuntime().

Now there is one side effect of this new system that may cause a hiccup for certain widgets. Previously, runtime detection was tied into the widget’s visibility. However, with the new system enterRuntime() and exitRuntime() are called regardless of whether the widget is visible or not. Again, I’ll go more into this in a later post.

Everything Else

Besides those features there are a number of small additions:

Features

  • Slide Label features can now be used in all versions of Captivate. However, they still can’t be used when Captivate’s accessibility features are turned off.
  • New property itemName allows you to read the item name the Captivate Author gave the widget (Note: At runtime InteractiveWidgets get a suffix added to the end of their name, which leads me to…).
  • New constant INTERACTIVE_WIDGET_SUFFIX holds the suffix that Captivate slaps on the end of Interactive Widget item names (The suffix is: _iWidgetAS3)
  • Eliminated the need for translatePropertiesXML(). Properties are now translated the first time you access them at runtime.
  • New property isCaptivate4Embedded indicates if the widget is embedded into a Captivate 4 movie (rather than being externalized).
  • Added new WidgetEvent INTERACTIVE_WIDGET_SUBMITTED event which is dispatched when an InteractiveWidget sets success or failure.
  • Added new WidgetEvent RESET_CRITERIA event which is dispatched when an InteractiveWidget calls resetCriteria().
  • Added new property captivateMainTimeline, which is exactly the same as cpVariables, but with a more appropriate name.

Bug Fixes

  • Fixed bug where Widget Properties did not appear to be saved under certain circumstances in Captivate 5.
  • Fixed a bug regarding QuestionWidgets and failure levels.
  • Corrected spelling mistake on WidgetInfo property maxAttempts.
  • getSlideObjectByName() now takes into the account the possibility of the Interactive Widget suffix.

Known Bugs

  • If a question widget is on the first slide of the movie, the enableAnswers() Template Method will be called before enterRuntime().

That’s a lot of new stuff to play around with. Have fun!

Posted in Debugging, WidgetFactory Builds, Widgets | 2 Comments

Testing Your Widgets

I’m taking a break from Captivate family relations for a moment (they’re so sensitive!) to touch on a rather essential topic.

TESTING

You can do all the IDE fooling you want, but like it or not, at some point you have to test your widget where it’s intended to run (in case you don’t know (and it’s a little worrying if you don’t) that’s Captivate). Which means you’ll find problems, which means you’ll code solutions, which means you’ll publish a new version of the widget, which means you’ll need to update the widget in Captivate to the current version, which means you’ll test again, which means you’ll find problems, and you’ll start the process all over again.

This, not surprisingly, takes time, and in the cutthroat world or widget building (yeah… no) we want to maximize our efficiency right?

So here’s how I go about testing my widgets.

General Testing Setup

I have a directory on my system where I keep all my widget test files. In there I have three different Captivate projects. They are:

  • TestWidgetCP4
  • TestWidgetCP5
  • TestWidgetCP5_5

Usually I’ll do my main testing in Captivate 5 because Captivate 4 has no easy update feature, and Captivate 5.5 currently has some problems as regards updating widgets. I’ll only test in Captivate 4 or Captivate 5.5 for the sake of making sure the widget works in those versions.

Inside my TestWidgetCP5 file I have a specific structure, it goes like so:

Slide 1: Main Testing Slide

This slide holds the widget and any objects that it’s interacting with. It will be the first slide to appear in the published movie.

If I’ve got a number of widgets that I’m playing around with, I’ll create testing slides for each of them, then show and hide whichever one I’m currently working with.

Slide 2: Update Slide

This slide is hidden and contains an instance of each widget you’re testing. When you publish a new version of the widget, you’ll use the instance on this slide to update the widget.

Why? Because when you update a widget, the instance you use to update will lose its Widget Properties, while all other instances will not. If you directly updated the instance on the Main Testing Slide each time, then you’d waste a lot of time resetting its Widget Properties. However, if you update the one on this slide (which will never be seen in the movie) then you’ll save a lot of time.

Slide 3: Tracing Slide

This slide holds an instance of Whyves CPXray widget. Quite often while I’m testing one of my widgets, I’ll want to check whether a function on m_movie or a variable on the Captivate Main Timeline may hold the information I need to access. This is what Monster Debugger is perfect for. Generally this slide will be hidden. But when I want to check something, it’s simply a matter of hiding the Main Testing Slide and showing this one.

Slide 4: Rewind Slide

This slide is placed right at the end of the movie and has a single button on it. On success that button will make the movie ‘Go To Previous Slide’. This makes it quick and easy to test if your widget works when the movie has been rewound.

Testing in Captivate 4

Testing in Captivate 5 is a dream, but when it comes to Captivate 4, it becomes a lot more time consuming. As I mentioned above, Captivate 4 has no formal update function. In order to bring in a new version of your widget, you have to delete the current instance, reimport the new version, then configure your Widget Properties again. It takes FOREVER!

But there are a few cheats you can use to speed up testing in Captivate 4.

New Widget – Same Slide

If your widget accesses slide objects at runtime, then make sure when you import in a new version of the widget you bring it in to the same slide. This will save you a lot of time otherwise spent in creating the objects and naming them again (this is especially true if you follow the next step).

Bad News: If your widget is a Question Widget, then you’re sunk. Each time you re-add it to the movie, Captivate will create a new slide for it to operate on.

Set Up Default Properties

To save yourself the time and pain of having to configure properties each time you import your widget, you can hard code default properties. If you’re already using the Widget King Widget Properties Method in your widget, then you may already have default properties.

The trick is to change those default properties to the settings that you’re currently testing in your widget. That way when you import the widget into Captivate 4, all you have to do is zip over to the Widget Parameters tab, which will write the default properties, and click OK.

Publish the movie, and then if everything is set up right you should be able to test your widget instantly.

If your widget deals with slide objects, then remember you can hard code the names of the slide object into the default properties. If you’re importing the widget to the same slide, then all the slide objects will have the same name and will link up with the widget.

One Last Thing

This may seem like splitting hairs, but my preferred way of testing the widget is to hit F12 which will publish the movie and open it up in a browser. I prefer this over the traditional publish dialog because that spits up dialog after dialog while publishing the movie.

I don’t use the in-Captivate preview a whole lot, because there are subtle differences between the preview movie and the published version.

So that’s a little about my setup for testing. In a future post I will write about a number of things that are important to test before you release your widget.

Stay tuned!

Posted in Testing, Widgets | Tagged , , | Leave a comment

Meet the Captivate Family – The Manager

In the last post we got an introduction to the everyday ordinary slide, and how it fits into the Captivate Movie. However, Captivate Movies are rarely made out of one slide. More often than not they’re made out of A-MILLION-BAJILLION SLIDZE! (Note: WidgetFactory, Infosemantics, and the Widget King do not in any way sanction or encourage the use of ‘A-MILLION-BAJILLION’ slides in a single Captivate Movie. Use imaginary numbers of slides in your movie at your own risk).

With the possibility for that many slides in a single movie, managing them gets very complex. That’s why this week we’re going to look at a little object which keeps those slides in line!

Ladies and Gentlemen, meet Ms’ Movie Controller.

Meet the Control Freak

Previously we illustrated the Captivate Movie as being a family talent show. Well now let’s say that due to overwhelming critical success, the Captivate family have decided to take their show on the road!

However, it’s not as simple as doing the same song and dance routine on a giant stage in front of 6,000 people. No, no, they need to be organized about this! So the first thing they do is hire Ms’ Movie Controller to manage the acts and keep those slides in line. And no wonder, just look at her.

MsMovieController

Would you dare cross her?

With her reputation slides obey her command without question. But what makes her fabulous at her job is not her dominating attitude, but her intimate knowledge of the show. She can tell you immediately the current slide, frame, frame rate, movie height/width, number of slides, Captivate Version… and almost any other peice of the information you could ever want.

She isn’t in charge of the movie, but she’s the go to person when you want something to happen.

Seriously, this is a gal you want on speed dial.

How to Access the Movie Controller

Every slide has a property called m_movie, which holds a reference to the Movie Controller. You may be needing the Movie Controller regularly, so it’s a good idea to save it to a variable. Here’s how you’d do that:

1
var movieController:Object = widgetSlide.m_movie

Here I used the widgetSlide to access the Movie Controller, but you could access it through any slide.

The Remote Control

Here are all the unique methods on the m_movie object. Many are self explanatory. Others are a bit vague. I’ve marked the ones I’ve found useful and given them a brief explanation.

  • addSlide()
  • clickHandlerLoaded()
  • closeFLVConnections()
  • Dofscommand()
  • exit() – Closes down the movie.
  • getCurrentFrame()
  • getCurrentSlide()
  • getCurrentSlideData() – This function returns a rdSlideData object that has the following properties:
    • m_playOnFrame: The number frame of the movie that the slide starts.
    • m_stopOnFrame: The number frame of the movie that the slide ends.
    • m_rdSlide_mc: A reference to the slide object.
  • getFrameCount()
  • getFrameRate()
  • getMovieHeight()
  • getMovieSlideCount()
  • getMovieWidth()
  • GetPlayingSlideIndex()
  • getSlide()
  • getSlideCount()
  • getSlideIndexFromFrame() – If you pass in a number to represent a frame in the Captivate movie, it will tell you which slide is supposed to be visible for that frame.
  • getSlidesInProject()
  • getTOCContainerMC() – (Not in Captivate 4)
  • getVersion()
  • gotoFlashFrame()
  • gotoFrameAndResume()
  • gotoMovieSlide()
  • gotoNextSlide()
  • gotoPreviousSlide()
  • gotoSlide()
  • gotoSlideAndResume()
  • hasPlaybar() – Returned false even though I had a playbar.
  • isMovieReady()
  • isPlaying() – Returns true if the movie is playing, false if it’s paused. Quite useful in some situations.
  • isTOCVisible() – Returns true if the TOC is out, false if it’s not. (Not in Captivate 4)
  • JumpToSlide()
  • markSlideAsCompletedForTOC() – (Not in Captivate 4)
  • movieonEnterFrame()
  • mute()
  • pause()
  • pauseMovie()
  • pauseOnInfo()
  • printCurrentFrame()
  • ReArrangeSlideData() – No idea what this one does, but it sounds scary.
  • relayoutTOC()  – (Not in Captivate 4)
  • RestoreMovieState()
  • resume()
  • resumeMovie()
  • resumeOnInfo()
  • rewindAndPause()
  • rewindAndPlay()
  • setMovieSize()
  • SetPacemeker()
  • setSize()
  • showCC()
  • showInfo()
  • slideCompleted()
  • slideLoaded()

If that’s not enough for you. Here are the object’s properties:

  • m_clickHandler_mc
  • m_currFrame
  • m_currSlideIndex
  • m_fps
  • m_isPreviewForAudioDialog
  • m_itemToInitialVisibilityMap – (Not in Captivate 4)
  • m_keyHandler
  • m_movie_mc
  • m_OrigFPS
  • m_paused
  • m_QuizInfoLastSlidePointScored – (Not in Captivate 4)
  • m_quizPlaybackController
  • m_slideData_array
  • m_soundHandler
  • m_startPlaying
  • m_state
  • m_supportsSyncPlayback

Déjà vu

Some of you may find these properties and methods familiar. Yes, many of these operations or peices of information are accessible to Advanced Actions through Captivate Variables. What I believe is happening (and I can’t say for sure because I’m not a Captivate Developer) is that when you access or change one of these Captivate Variables, it diverts your request to the Movie Controller. For example, if you wanted to show the Closed Captions then usually you’d change the cpCmndCC variable like this:

1
cpVariables.cpCmndCC = 1

But what’s actually happening behind the scenes is the Captivate Main Timeline is calling the Movie Controller’s showCC() function.

As you can see, the Movie Controller has a lot of extra gems that have not been exposed via Captivate Variables. So I suggest you pull out your nearest test widget and have a good play Smile

Posted in Captivate Movie Structure, Captivate Variables, Widgets | Tagged , , , , | 13 Comments

Meet the Captivate Family – Slides

In the last post we learned about the Captivate Movie’s head honcho: The Captivate Main Timeline. Now it’s time to climb a little further down the family tree and meet the old man’s kids.

Ladies and Gentlemen, I give you: Slides.

What are Slides?

As users of Captivate, we think of slides as chapters in a book, each dealing with a specific topic. While that is true from a metaphorical point of view, from a technical point of view, a slide is a Display Object (Display Objects were explained in the previous post). The slide Display Object is a child to the Captivate Main Timeline.

MainTimelineKids

When the Captivate Main Timeline realizes the movie needs to move to another slide, it sets that slide appear, then tells the previous slide to disappear. So the Captivate Main Timeline controls which slide will be shown next. Whereas, slides control when their objects (Such as Captions, Highlight Boxes, Images…) will appear.

I find it helpful if you can think of the Captivate Movie like this:

A Show to End All Shows!

Slides are the Captivate Main Timeline’s sons and they’re in the film business.

SlideCaricature

All of them.

FamilyTree

And yes, in case you were wondering, they are all identical… er… Quadruplets.

What’s more, each of them are Dads too, and their kids are a real handful. Yep, they’ve got little Captions and Highlight Boxes running about at home.

The story goes that the Captivate Family are having a big reunion hosted at Grampa Timeline’s house. As part of the festivities, the grand-kids are to take part in one big talent show! However, each slide is assigned one act for all his kids to take part in. So it’s  up to Daddy slide to coordinate the family act. Yes he’s the one that has to make sure little Clarance the Caption can sing her song, while Herbie the Highlight Box can dance to it.

So although the slides never appear in the act (even the slide background is a separate Display Object that the slide has hired out) they are the managing force behind it.

TallentShowWhen one act finishes, it’s up to Old Man Timeline to decide who’s on next.

And that’s basically what the whole Captivate Movie is.

Getting a Hold of a Slide

So slides have an important place in the Captivate family. So how might we, when coding a widget, get a hold of a particular slide?

WidgetFactory has many tools for accessing slides.

The slide you’ll most commonly want to access is the slide the widget has been placed on. This can be accessed directly through the widgetSlide property.

However, if your widget is doing some behind the scenes calculations while its slide is not active, you can access the slide that is active through the currentSlide property.

But what if you just want to access the first slide, or a slide with a particular label, or you need to loop through the slides until you find a specific one, like the Quiz Results slide? In that case, you can use the getSlide() method. Just pass in the number, or label (though this will only work if the movie has Accessibility turned on), of the slide into the function, and it will return a reference to it. For Example: The next line of code will return you a reference to the first slide of the movie.

1
getSlide(1);

To store that slide reference in a variable, you’d write it like this:

1
2
3
import flash.display.MovieClip;

var firstSlide:MovieClip = getSlide(1);

So now that we know how to get a hold of our desired slide, what can we do with it?

Slide Features

Slides have a number of objects and methods that widget developers will find useful. There are a few properties…

  • m_paused (Boolean): Indicates whether the slide is paused or not.
  • m_projectSlideIndex (int): Holds the slide’s number (this value is zero based, so the first slide would be 0, the second would be 1, and so on)
  • m_movie: A very interesting object that is essentially a remote control for the whole movie. I’ll be writing more about this in a future post.

…But methods are really where it’s at for slides. Here are some of the handy ones:

  • getSlideProperties() : Returns an object that has the following properties.
    • startFrame (int): The frame of the movie that this slide starts on.
    • endFrame (int): The frame of the movie that this slide ends on.
    • slideTyle (String): A string that describes what sort of slide this is.
    • slideHandle: A proxy object of the slide.
  • getSlideDatabaseId() : Returns a number which… is some sort of database ID.
  • hasSlideAudio() : Returns a Boolean which indicates whether this slide has audio.
  • isSlideActive() : Returns a Boolean which indicates whether this slide is currently being viewed or not.
  • isSlidelet() : Returns a Boolean which indicates whether this slide is actually a slidelet.
  • nextSlide() : Jumps the movie to the next slide.
  • previousSlide() : Jumps the movie to the previous slide.
  • resumeSlide() : If the slide has been paused, this starts it playing again.

It’s a Slippery World Out There

Today we’ve learnt a lot about the common slide. However there are many varieties of slides, like: Quiz slides, Animation Slides, Image Slides, PowerPoint Slides, Recording Slides, and Master Slides. In the future, we may take a more in depth look at what makes these slides unique, and how you can use them to your advantage.

Posted in Captivate Movie Structure, Theory, Widgets | Tagged , , , , , | 1 Comment

Meet the Captivate Family–Old Man Timeline

Have you ever had one of those ‘Let’s Meet the In-Laws’ dinners? Kinda awkward aren’t they? Often we fail to realize how stunningly varied the human race is until we share a meal with those soon to be related to us.

Think of the Captivate movie as a family. Not necessarily one you’re about to be forcibly related to, but one you have to deal with on a day to day basis.

The Captivate Movie family is made up of many members, each with their own role and peculiar quirks. Over the next couple of weeks, I’ll be introducing you to each member in turn. But first, let’s take a look at how this illustration works on a technical level.

Display Objects and their Relatives

In the world of Flash (and by extension Captivate), anything in the swf we can see is called a Display Object. However, just because you have a Display Object doesn’t mean that you can see it. For a Display Object to be seen, it must be added to the Display List (think of it like marrying into the family).

Don’t let the word ‘list’ fool you into thinking it’s just a scrap of paper with a few Display Objects scribbled over it. Oh no, the Display List is structured man! Right at the top of the Display List is a root Display Object (known as the Main Timeline). All other Display Objects must descend as ‘children’ from the Main Timeline.

MainTimeline

These Display Objects can have children of their own. In that case, the top Display Object becomes the ‘parent’ of the ‘child’ Display Object.

ParentChild

So by that logic, the Main Timeline is parent to all Display Object.

Now if we did something to a parent, such as change its location, then this would affect the child too. If the parent were to be rendered pink, then the child would be also. If we added a blur filter to the parent, then the child would also be blurred.

Note though, that if the parent is not in some way a child of the Main Timeline, then the child isn’t considered as being part of the Display List either; and remember, if it’s not on the Display List, then it isn’t seen.AstrangedChild

Thus we end up with the great family tree which is Captivate.

Now let’s get to know the man at the top a bit better.

Old Man Timeline

Old Man Captivate Timeline has been around for donkeys years, but he hasn’t gone soft. No, he’s the main organizing force behind the entire Captivate Movie. If Captivate could be likened to the mob, he’d be the Godfather.

CPTimelineCaricature

This is the guy who decides (from his mouldy brown corduroy recliner) when and which slides are shown. He also keeps a tight hold on the Captivate Variables (system or user). If you want to access them, you’re going to have to go through him first.

The Captivate TOC and Playbar are direct children of Old Man Timeline. That is unless the movie is inside an aggregated project, which is a WHOLE other type of family.

Also held closely to his chest is the movieXML. This is data that is written by Captivate (the software program) and incorporated into the published movie. It contains information about general settings for the movie and each of its slides. It also contains data for each object on every slide. If you want to have some fun, I suggest you pick up your nearest copy of De Monster Debugger and trace out the movieXML.

1
MonsterDebugger.trace(this, cpVariables.movieXML);

Oh, which reminds me. The Captivate Main Timeline is accessible in WidgetFactory through the cpVariables property. The property is called this (instead of captivateMainTimeline) because you’re most likely to access it to get hold of a Captivate Variable.

Now that we’ve met the head honcho, in the next post we’ll get acquainted with some of his kids: Slides.

Posted in Captivate Movie Structure, Theory, Widgets | Tagged , , , , , , | 4 Comments

Interactive Widgets

And now, after long delay, I give you:

ThatsAllFolks

Previously we discussed WHAT makes and Interactive Widget interactive, but now we shall see HOW to make an Interactive Widget interactive.

It All Comes Down To This…

Unlike Static Widgets who merrily prance about the Captivate Movie doing whatever they jolly well want, Interactive Widgets have a duty to perform.

What is their duty? To report whether the audience succeeded or failed to Captivate. For what purpose?

SuccessFailure

When the widget reports success, Captivate will trigger the On Success action as defined by the Captivate Author. When the widget reports failure, Captivate will strike away one of the attempts allowed for the audience. If the audience uses up all their attempts, the Last Attempt action will take place. Captivate manages these actions. All Interactive Widgets are concerned about is reporting the success or failure. Deciding what qualifies as success or failure is what makes each Interactive Widget unique.

Although Static Widgets have the greatest number of possibilities, I find that Interactive Widgets generally give the Captivate Author more creative control. Allowing the Captivate Author to decide what happens when a button is clicked/timer goes off/alien space ships are destroyed, allows for a lot of possibilities.

How to Create an Interactive Widget

You can create an Interactive Widget the same way you create a Static Widget. With the exception of extending the InteractiveWidget class instead of StaticWidget.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package
{
    import widgetfactory.InteractiveWidget;
   
    public class EasyInteractiveWidget extends InteractiveWidget
    {
       
        public function EasyInteractiveWidget() {
            trace("Hello World!");
        }
       
    }
   
}

How to Succeed and How to Fail

When your widget is at runtime, you can report success by calling the setSuccess() method.

1
setSuccess();

On the other hand, to report failure you’d call the setFailure() method.

1
setFailure();

So if you wanted to build a widget that would report success as soon as it appears in the movie, it would look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package
{
    import widgetfactory.InteractiveWidget;
   
    public class ImmediateSuccess extends InteractiveWidget
    {
               
        override protected function enterRuntime():void
        {
            setSuccess();
        }
       
    }
   
}

The above widget can be quite useful in itself if you wanted to trigger an Advanced Action without the audience having to do something first.

That’s all you really need to know to go off and build your own Interactive Widget right now. It’s amazingly simple.

Play it Again Sam

One Interactive Widget annoyance is that you can only trigger the success of failure action once. Take this widget for example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package
{
    import widgetfactory.InteractiveWidget;
    import flash.events.MouseEvent;
    import fl.controls.Button;
   
    public class ButtonSuccess extends InteractiveWidget
    {
        override protected function enterRuntime():void
        {
            var button:Button = new Button();
            addChild(button);
            button.label = "Click Me!";
           
            button.addEventListener(MouseEvent.CLICK, onButtonClicked);
        }
       
        private function onButtonClicked(e:MouseEvent):void
        {
            setSuccess();
        }
    }
}

All it has is a button which once clicked will notify Captivate of success. See it in action below.

Get Adobe Flash player

When you click the button again, nothing happens, because you’ve used up your turn. You can only reset the Interactive Widget’s criteria by rewinding the movie to a point before the widget appears.

But what if we wanted the success action to happen every time we clicked the button, rewind or no rewind? Well now with WidgetFactory 5.1 you can!

Interactive Widgets have a new method called resetCriteria() which allows you to submit success, or failure, again!

If we call resetCriteria() right after calling setSuccess()…

1
2
3
4
5
private function onButtonClicked(e:MouseEvent):void
{
    setSuccess();
    resetCriteria();
}

…Then each time we click the button the success criteria will be fulfilled again!

Get Adobe Flash player

This opens up a lot more possibilities for Interactive Widgets. (Advanced Action loops anybody?)

Hint Hint

One last feature of Interactive Widgets is the Hint Caption.

HintCaption

You can display the hint caption with the showHint() method, and then hide it again with hideHint().

I mention this only in passing because it’s not as cool as the stuff above. Thought it could be a neat little feature to include in some widgets. For example: If you built a count down widget, you could have the option to display the hint caption a minute before the countdown ends (with FAILURE!).

So there you go. Everything you wanted to know about Interactive Widgets but weren’t afraid to ask!

That’s all folks!

Posted in Basics, Interactive Widgets, Widgets | Tagged , , , , | 7 Comments