Archive for category ActionScript

Determining whether a SWF is running in the IDE or a browser

Here’s something that’s been around for a while that I didn’t learn about until just recently.

The flash.system.capabilities.playerType property can be used to tell whether you’re running in the browser, a standalone player, or the Flash IDE. It returns the following values (from Adobe’s documentation):

  • “ActiveX” for the Flash Player ActiveX control used by Microsoft Internet Explorer
  • “Desktop” for the Adobe AIR runtime (except for SWF content loaded by an HTML page, which has Capabilities.playerType set to “PlugIn”)
  • “External” for the external Flash Player or in test mode
  • “PlugIn” for the Flash Player browser plug-in (and for SWF content loaded by an HTML page in an AIR application)
  • “StandAlone” for the stand-alone Flash Player

Simply check for (flash.system.capabilities.playerType == "ActiveX" || flash.system.capabilities.playerType == "PlugIn") and you’ll know you’re in a browser.

, , ,

Leave a comment

Disabling the FLVPlayback component’s controls (including seekbar!)

I’ve stumbled on another one of those “everyone wants to do it, but nobody knows how” issues in Flash: how to disable the controls on the FLVPlayback component.

After quite a bit of documentation-reading, web-searching, and forum-browsing, I’ve come up with a function for easy, on-the-fly toggling of controller-enable-ability.

with a FLVPlayback instance on the stage, add the following to your ActionScript:

 mx.video.FLVPlayback.prototype.enableButtons = function(bEnabled:Boolean){
this.skin_mc.seekBar_mc.handle_mc._visible = bEnabled;
if(bEnabled){
this.stopButton =this.skin_mc.stop_mc;
this.backButton = this.skin_mc.back_mc;
this.forwardButton = this.skin_mc.forward_mc;
this.seekBar = this.skin_mc.seekBar_mc;
}else{
this.onEnterFrame = function(){
this.stopButton = this.skin_mc.stop_mc.disabled_mc
this.backButton = this.skin_mc.back_mc.disabled_mc;
this.forwardButton = this.skin_mc.forward_mc.disabled_mc;
this.seekBar = null;
updateAfterEvent();
delete this.onEnterFrame;
}
}
}

Now, for a bit of explanation:

The first step is to simply toggle the visibility of the SeekBar handle. With it invisible, there is no way the user can use it, and this seems to be the simplest solution, rather than digging through the MC structure of a component skin and figuring out how that handle is, uh, handled. So, the bEnabled value can double as the visibility value for the handled: true (visible) for enabled buttons, or false (invisible) for disabled.

For the rest of the buttons, it’s not so simple. Users have come to expect a “ghosted” or “grayed-out” appearance for a disabled button, so simply removing them as we did with the scrollbar handle would be bad form. Luckily, the pre-made skin SWFs for the FLVplayback component include disabled states for everything, and we can use these.

Because the component skins use bitmap caching and 9-slice scaling to maximize their flexibility, simply setting the button properties to the disabled MC won’t work, and it requires a bit more of a brute-force approach to get those buttons to appear. Hence, the onEnterFrame and updateAfterEvent() commands. updateAfterEvent() forces an update of the stage, so it will make those disabled-states appear, but it only works as part of a clip event, such as onEnterFrame. So we wrap the whole thing in an onEnterFrame, and then delete the onEnterFrame function to save on processing and memory.

I should note that I developed this using the SteelExternalAll.swf skin. The documentation indicates that the skins are built using a universal structure, so it should work for any of them, but I’m not making any promises.

, , , ,

6 Comments

Customing icons on the Flash 8 Tree Component

Back to one of my favorite topics – UI Component customization. Flash’s Tree Component provides a Windows Explorer-like hierarchical menu for displaying data in a “folder” structure.

The structure it displays uses 2 separate icons, a “folder” icon for folder nodes, and a “disclosure” arrow for opening and closing the folders.

To see an example of this, place a tree component on the stage and give it an instance name of “myTree.” Then, use the following loops for some dummy data in the tree:

for(i=1;i

The Tree Component Documentation lists various styles that can be set on the component, and it seems that these properties work without first installing a theme.

I’m not sure the exact reason for this, but the component seems to want to open and close folders based on clicking the “disclosure” arrow, not the folder icon.

So, what if you wanted one icon only? For this example, I’ll use the +/- metaphor that the Windows registry and some other apps use. first, create your “plus” and “minus” movie clips, and give them linkage IDs of “plus” and “minus”, respectively.

Then, use setStyle to apply these to the tree:

myTree.setStyle("disclosureOpenIcon","minus");
myTree.setStyle("disclosureClosedIcon","plus");

This turns the disclosure arrows into plus an minus signs, but the cliché folders are still there:

tree_plusd_w_folders.gif

The solution is to create a blank movieclip and set it as the folder icon. To do this, create a new MovieClip symbol and give it a linkage ID of “blankicon.” Then, add the following to assign the empty icon:

myTree.setStyle("folderOpenIcon","blankicon");
myTree.setStyle("folderClosedIcon","blankicon"); 

And there you have it…

tree_plusminus_final.gif

, , ,

Leave a comment

A Better Way To Determine a Function’s Caller

There are some rare instances, mainly during debugging, where you may need to determine which function called the current function. For example, you may have a function that is repeatedly called at many places in your code, and you need to determine which function calls it at a specific time.

ActionScript provides arguments.caller for this. However, using arguments.caller returns only a reference to the caller function, and leaves out details such as its name, type, etc. Take a look at this example:

function test(){
	trace("this function was called by " + arguments.caller);
}
function callTest(){
	test();
}
callTest();

The output of this is:

this function was called by [type Function]

Um, thanks, I guess.

My function was called by a function. This is about as helpful as [Object object] or, my personal favorite, “undefined is not defined.”

The trace output is giving us a [type Function] because it’s the only way Flash can trace a reference. The way around this is to check the reference against everything and test for equality. Let’s add a new function to the above code:

function getCaller(callerObj){
	var str:String = callerObj + newline + "";
	for(i in _root){
		if(callerObj == _root[i]) {
			return i.toString();
		}
	}
}

function test(){
	trace("this function was called by " + getCaller(arguments.caller));
}
function callTest(){
	test();
}
callTest();

The output has changed for the better:

this function was called by callTest

Presto! You’ve gotten your caller function’s name. The getCaller function is looping through everything in _root. When the loop encounters a function, it is really encountering a reference to that function, just like arguments.caller is a reference to the caller function. Therefore, the if statement is comparing references to references and is able to accurately determine whether the caller property passed to it is the same as an existing function, and then return its name (or, more accurately, the name of the index of that reference in the _root object) as a string.

Please keep in mind, however….

This method is not perfect. I’ll admit it. It only works for functions that are defined on a frame in the main timeline. It won’t work for anonymous (inline) functions, calls made from a nested object such as a movie clip, component, or class, or outside calls coming in from JavaScript or any other external interface.

None of these flaws are unfixable, and time permitting, I’ll work on ways to improve this method, but the basic concept of this code (comparing references) will remain the same.

,

1 Comment

  • Least-Old Tweets

    Error: Twitter did not respond. Please wait a few minutes and refresh this page.