The two main Widget Modes are Runtime and the Properties Dialog. These are essential to have a working widget. However, they are not the only widget modes. So in this post, we’re going to look at one of the more obscure widget modes.
The Widget Panel Preview.
What is it?
The Widget Panel (found under the Window > Widget menu in Captivate) lists the widgets in the Captivate Gallery folder. To find this folder, go to Program Files and into Adobe\Adobe Captivate 5\Gallery\Widgets. If you insert your widget here, it will appear in the list next time it is refreshed.
When you select one of the widgets, the window above the list will display a ‘preview’ of the widget. This preview could range anything from a splash screen, to a detailed tutorial, or maybe even a help system. Either way, what’s actually being shown here is the widget swf. Which means we need to program the screen ourselves.
How do we build it?
To make something happen in the preview window, write it in the enterWidgetPanelPreview() Template Method.
1 2 3 4 | override protected function enterWidgetPanelPreview():void { } |
When WidgetFactory detects that the widget swf is being displayed in the widget panel, it will call this function and thus the code inside it will run.
For me I like to keep my preview screen simple. I usually have the widget’s name up top, a logo in the middle, and a link to the company website down the bottom. All told, that code looks similar to this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | override protected function enterWidgetPanelPreview():void { ////// The Title text field. var title:TextField = createTextField("Widget Panel Testing Widget", 16, true); title.x = stage.stageWidth / 2 - title.width / 2; title.y = 25; ////// Logo graphic var logo:Sprite = new Sprite(); // Usually we wouldn't draw our own logo. But we will for this example. logo.graphics.beginFill(0xFF0000); // Fill colour logo.graphics.lineStyle(3, 0x000000, 1); // Line thickness, colour, alpha // Draws a 100x100 rectangle in the centre of the Sprite logo.graphics.drawRect( -50, -50, 100, 100); logo.graphics.endFill(); addChild(logo); logo.x = stage.stageWidth / 2; logo.y = 125; ////// The Company Link text field. var link:TextField = createTextField("By the Widget King", 12, false, "<a href="http://www.infosemantics.com.au/widgetking/");">http://www.infosemantics.com.au/widgetking/");</a> link.x = stage.stageWidth / 2 - link.width / 2; link.y = 200; } // This function takes care for the usual text field operations. private function createTextField(text:String, size:int, bold:Boolean, link:String = ''):TextField { var tf:TextField = new TextField(); addChild(tf); tf.defaultTextFormat = new TextFormat("Verdana", size, 0x000000, bold, null, null, link); tf.text = text; tf.autoSize = TextFieldAutoSize.CENTER; return tf; } |
The above code yields this Widget Panel preview screen.
As far as looks go, it’s okay. However, there is one BIG problem. The Widget Panel is resizable. And if you resize the window, this screen will no longer be laid out correctly.
Working with Resizable Windows
To get our screen to resize correctly, we use much the same method as any other resizable swf window. First, you set the stage’s scale mode to NO_SCALE; which WidgetFactory already does for you. NO_SCALE means flash won’t try and resize the swf by itself, instead it will dispatch an Event.RESIZE event each time the stage size changes so that we can listen for it and deal with the resizing.
For more information about working with events, see this post.
1 |
Note: This event is dispatched from the stage.
Now inside the handler (the onStageResize function passed in above) we reposition the elements (the tile, logo, and link) to align to the new stage size. So we move all the code that positions the on screen elements from enterWidgetPanelPreview() into the onStageResize() function.
1 2 3 4 5 6 7 8 9 10 11 | private function onStageResize(e:Event):void { title.x = stage.stageWidth / 2 - title.width / 2; title.y = 25; logo.x = stage.stageWidth / 2; logo.y = 125; link.x = stage.stageWidth / 2 - link.width / 2; link.y = 200; } |
If you’re following along, then you’re going to have to make the title, logo, and link objects into class variables so that they can be accessed outside the enterWidgetPanelPreview() function.
Because we’ve horizontally position the objects according to the stage’s width, the screen will look find if we resize the preview horizontally. However, because all the y (vertical) locations have been hard coded, the elements will always stay at the same height despite the stage’s size. So the lesson is: When you’re dealing with resizable windows, always position your elements according to the stage width and height.
Let’s make it so that the title is positioned at an eighth of the stage height, the logo at half the stage height (putting it in the centre), and the link at seven eigths of the stage height to balance out the title.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private function onStageResize(e:Event = null):void { // Title is 1 eigth down the stage. title.x = stage.stageWidth / 2 - title.width / 2; title.y = stage.stageHeight / 8; // Logo is halfway down the stage. logo.x = stage.stageWidth / 2; logo.y = stage.stageHeight / 2; // Link is seven eigths down the stage. link.x = stage.stageWidth / 2 - link.width / 2; link.y = stage.stageHeight - stage.stageHeight / 8; } |
Now when you resize the Widget Panel’s Preview, the layout remains constant.
One more thing. Seeing as the positioning code has been moved to the onStageResize() function, the objects aren’t aligned until the screen is resized. This means before you resize the stage you see this:
To position the objects without duplicating the positioning code, we’ll call the onStageResize function during the initial set up.
1 2 3 4 5 6 | override protected function enterWidgetPanelPreview():void { ///.... Other stuff in this function. onStageResize(); } |
onStageResize() has been built to respond to an event, and is therefore expecting an event object to be passed into it.
1 |
The (e:Event) means an error would be caused if we tried to call onStageResize() without passing in an event object. To get around this, we give the e parameter a default value; making passing something in optional.
1 |
Here’s the complete code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | package { import flash.display.Sprite; import flash.events.Event; import flash.text.TextFieldAutoSize; import flash.text.TextField; import flash.text.TextFormat; import widgetfactory.StaticWidget; public class TestWidgetPanelPreview extends StaticWidget { private var title:TextField; private var logo:Sprite; private var link:TextField; public function TestWidgetPanelPreview() { ///// Uncomment next line to test the preview screen. //enterWidgetPanelPreview(); } override protected function enterWidgetPanelPreview():void { ////// The Title text field. title = createTextField("Widget Panel Testing Widget", 16, true); ////// Logo graphic logo = new Sprite(); // Usually we wouldn't draw our own logo. But we will for this example. logo.graphics.beginFill(0xFF0000); // Fill colour logo.graphics.lineStyle(3, 0x000000, 1); // Line thickness, colour, alpha // Draws a 100x100 rectangle in the centre of the spirte logo.graphics.drawRect( -50, -50, 100, 100); logo.graphics.endFill(); addChild(logo); ////// The Company Link text field. link = createTextField("By the Widget King", 12, false, "<a href="http://www.infosemantics.com.au/widgetking/");">http://www.infosemantics.com.au/widgetking/");</a> stage.addEventListener(Event.RESIZE, onStageResize); onStageResize(); } private function onStageResize(e:Event = null):void { // Title is 1 eigth down the stage. title.x = stage.stageWidth / 2 - title.width / 2; title.y = stage.stageHeight / 8; // Logo is halfway down the stage. logo.x = stage.stageWidth / 2; logo.y = stage.stageHeight / 2; // Link is seven eigths down the stage. link.x = stage.stageWidth / 2 - link.width / 2; link.y = stage.stageHeight - stage.stageHeight / 8; } // This function creates a formatted text field to allow us to make the text above quicker. private function createTextField(text:String, size:int, bold:Boolean, link:String = ''):TextField { var tf:TextField = new TextField(); addChild(tf); tf.defaultTextFormat = new TextFormat("Verdana", size, 0x000000, bold, null, null, link); tf.text = text; tf.autoSize = TextFieldAutoSize.CENTER; return tf; } } } |
Click here to download the widget files.
On a final note and warning, Captivate 5′s Widget Panel Preview screen is a little unpredictable. Sometimes it works, other times doesn’t show up at all. Usually when I want to see if my interface is working I test it in Captivate 4.

