Skip to main content
Inspiring
July 27, 2010
Answered

Cp5 Widget Development - Widget appearing on stage, event needed

  • July 27, 2010
  • 2 replies
  • 1724 views

First a caveat: I'm returning to Actionscript after after not touching it for a few years so I'm a bit rusty!

Problem: need an elegant method to tell when a Widget has appeared on the stage

A good example of why you might need this is the bundled Timer widget that comes with Captivate - it only starts when the widget appears on stage.  Other things might be for example dealing with Captivate variables for more advanced branching schemes, but only at a point in the timeline when you know those variables are in the state they need to be.

So, the timer widget accomplishes this task, what's the problem?  The problem is the method it uses is pretty inelegant in that an event listener is used on the ENTER_FRAME event to check on every frame the CPMovieHandle property isWidgetEnabled, and if it is, remove the event listener and start the timer.

From my testing, a widget gets initialised on frame 0 of the Captivate timeline irrespective of which slide the widget is on, so the above event listener is enabled and using resources right from frame 0.  Multiply that up by several widgets and you can see what an inelegant solution that is especially if your widget(s) appear within the last few slides.

So, my question; is it possible to somehow extend one of the Captivate classes to raise an event when the widget 'becomes enabled', and render all that ENTER_FRAME stuff redundant?  OR is there an undocumented event for what I want (ever hopeful!!)?

One idea I had was to use the CPSlideEnterEvent to only start the ENTER_FRAME listener on the slide that the widget was on - that fell flat as I could not find a way of determining programmatically which slide the widget was on

Any ideas anyone?

This topic has been closed for replies.
Correct answer Whyves

Hi,

The CPMovieHandle class is a proxy so it will not be very usefull to you. Since you seem familiar with classes, I suspect that all of your code is in an external class or are you coding on the timeline? If it is in an external class, you just need to write this line:

        override public function set visible(value:Boolean):void {
            super.visible = value;
            // Enter your detection code here
        }

You can add your timer there and the widget will turn it's visibility to on within 200 ms. As for knowing which slide the widget is on, you can use this code:

       
        private function findParentSlide(widget:DisplayObject):* {
            var currentTarget:DisplayObjectContainer = widget.parent;
            while (currentTarget != null) {
                if (currentTarget.toString().toLowerCase().indexOf("slide") >= 0) return currentTarget;
                currentTarget = currentTarget.parent;
            }
            return null; // We're at the root
        }

You provide this function with the widget reference. It will return the parent slide or null if it didn't find any slide.

HTH

Whyves

_____________________________

www.flash-factor.com

2 replies

Mr_BlokeAuthor
Inspiring
August 10, 2010

For anyone interested, Tristan Ward has included this functionality in his Widget Factory API as both an event and a protected method (both called enterRuntime).

Tristan's superb API can be downloaded from google code here: http://code.google.com/p/widgetfactory/

with full documentation here: http://www.infosemantics.com.au/widgetfactory/doco/index.html

The Widget Factory API is full of lots of widgety goodness and is a real asset to anyone wanting to develop their own widgets for both Cp4 and Cp5 - If you've not checked it out yet, I urge you to do so.

Inspiring
July 30, 2010

Hi,

Cp5 sets the Visible property of the widget to true before displaying it. You should override the Visible property and detect when it is beeing shown. You can also walk up in the display object hierarchy and find the slide on which it is located. I think that the slide if of type "rdSlide". This way you would know on which slide you're on.

HTH

Whyes

___________________________

www.flash-factor.com

Mr_BlokeAuthor
Inspiring
August 2, 2010

Yeah that was sort of what I was thinking but I just don't know how to override it.  Looking in the CPMovieHandle Class file the important bits are the constructor:

public function CPMovieHandle(aWidgetParams:Function=null,aReplaceVariables:Function=null,aGetContainerProps:Function=null,
            aGetSlideProps:Function=null,aGetMovieProps:Function=null,aIsWidgetVisible:Function=null,aIsWidgetEnabled:Function=null)
        {
            _widgetParams = aWidgetParams;
            _replaceVariables = aReplaceVariables;
            _getContainerProps = aGetContainerProps;
            _getSlideProps = aGetSlideProps;
            _getMovieProps = aGetMovieProps;
            _isWidgetVisible = aIsWidgetVisible;
            _isWidgetEnabled = aIsWidgetEnabled;
        }

and the public method isWidgetEnabled:

public function isWidgetEnabled():Boolean
        {
            var lEnabled:Boolean = false;
            if( _isWidgetEnabled != null )
            {
                lEnabled = _isWidgetEnabled();
            }
            return lEnabled;
        }

It is the reference to "aIsWidgetEnabled" which is confusing me, and that is what I think I really need to override - but how?  Not knowing what that is or what it does I can't override it safely and will probably just end up breaking something.  I'm reaching the limit of both my OO and Actionscript skills here and need a little help

Regarding the slide numbering,  I can easily find out which slide I'm on at runtime but what I can't do is find out which slide the widget is placed on when the widget is initialised (which appears to be frame 0 of the captivate timeline and therefore always returns the first slide).   Bear in mind this is only a possible workaround for the above problem and if that was cracked I wouldn't need this.

I probably should have described it a littler clearer:  The idea was when the widget was initialised it checked to see which slide it was on and stored that.  It would then add an event listener for the CPSlideEnterEvent with a function that checked the current slide number (that's the easy bit, and what you are also suggesting) against the stored slide number that the widget is on, and if they match, add the event listener for the enterFrame event.  That way the enterFrame event listener would not be running from frame 0 of the captivate timeline (also important if several widgets employ similar functionality)

I hope that makes sense!

Anyway, the better (and preferred by me) solution is the override idea with a custom event - I just don't know how to achieve that.

So once again, any more ideas or code examples anyone???

WhyvesCorrect answer
Inspiring
August 3, 2010

Hi,

The CPMovieHandle class is a proxy so it will not be very usefull to you. Since you seem familiar with classes, I suspect that all of your code is in an external class or are you coding on the timeline? If it is in an external class, you just need to write this line:

        override public function set visible(value:Boolean):void {
            super.visible = value;
            // Enter your detection code here
        }

You can add your timer there and the widget will turn it's visibility to on within 200 ms. As for knowing which slide the widget is on, you can use this code:

       
        private function findParentSlide(widget:DisplayObject):* {
            var currentTarget:DisplayObjectContainer = widget.parent;
            while (currentTarget != null) {
                if (currentTarget.toString().toLowerCase().indexOf("slide") >= 0) return currentTarget;
                currentTarget = currentTarget.parent;
            }
            return null; // We're at the root
        }

You provide this function with the widget reference. It will return the parent slide or null if it didn't find any slide.

HTH

Whyves

_____________________________

www.flash-factor.com