Thursday, 6 January 2011

Usability: Click and Drag cursor

Although it's a common feature in many flash applications a little feedback for users is always welcome... specially when you have a "click and drag" situation.

Recently I came across this request for an infography for a client. I make the infography, but the application didn't have a feedback for the user that that area was meant to be draggable, only a small phrase stating that.

I agreed that this would make sense and made the change.

To substitute the regular Windows mouse icon with one of your own, you must first import the class that controls the mouse UI options, like this:

import flash.ui.Mouse;

This class let's you use two important features for mouse icon... the hide and show options.

If you put it like this:
Mouse.hide();

The mouse icon will disappear, although the mouse still works, but you don't know where it is.

The reverse option will be the show option, like this:
Mouse.show();

You must import also the MouseEvent class, to set the listeners later:
import flash.events.MouseEvent;

Now that we have our hide and show options, how can you make a custom icon and make it follow the mouse position?

Making it simple you have to add a listener for the mouse position, but this is made indirectly, since we are going to listen for any mouse move, and then see where it is.
Making an EnterFrame event can be costly specially if you're application has many pictures or video, like the one I had to make, so we're listening for any mouse move, which is triggered when... you guessed it... the mouse is moved.

First of all, make a movieclip with the icon you wish to appear, and place it in the library with a export actionscript name. I will call it MyLibraryCursor (remember that when making the movieclip, the "plus" sign indicates where will be the click spot for the mouse).

Make a new object with this Library Class:
public var myCursor:MyLibraryCursor;

Then on the init() function of your main class, define your new object, along with two important options:
myCursor = new MyLibraryCursor();
myCursor.mouseEnabled = false;
myCursor.mouseChildren = false;

mouseEnable tells flash if this object receives mouse behaviours. Usually that's a problem when you have many movieclips on the stage, where you can have problems with object focus (this will not disable mouse events).

mouseChildren is put there to prevent event bubbling. Has you know AS3 has a great feature, but sometimes difficult to control and understand, which is the propagation of events between children of a display object (bubbling). This prevents it from happening (a typical case of this is when you have a text box with text, and the mouse is only active when you pass by the line of a letter).

Next we will add the mouse movieclip to the stage:
addChild(Global.myCursor);

Make the "windows" mouse disappear:
Mouse.hide();

And then listen to the MOUSE_MOVE to make it follow the mouse:
this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);

This calls the mouseMoveHandler function which will move the custom icon to the mouse position:
public function mouseMoveHandler(evt:MouseEvent):void
{
myCursor.x = evt.stageX;
myCursor.y = evt.stageY;
}

And that's it, the basics for replacing the windows cursor, for one of you're own.

Possibly in a future post I will explain other option for this, cleaning a bit the behaviours about this.

You can make a Global class to easy the control of the mouse behaviour if you have to hide, show and turning off and on, between different display objects across your application... this maybe will to go for a later post.

Cheers. 

Sunday, 19 December 2010

MouseButton and HandCursor

Every now and then you may need to use a Sprite or MovieClip with a EventListener. And chances are that 99% of these times it will be a MouseEvent, since these objects are easy to place in custom classes and build an entire interface with Actionscript... at least that will be 100% of the times for me ;)

So in these cases you don't want to make Button objects, but still be able to feedback the user that in "this" object contains an action with the mouse.

Well simply placing three lines of code you can show your user the hand cursor (like it appears in a web page), and have the behaviour of a button. Furthermore the third line prevents the hand cursor not to be active if the button has text in it. Those lines go like this:


var button:MovieClip = new MovieClip();
button.buttonMode  = true;
button.useHandCursor = true;
button.mouseChildren=false;
addChild(button);

Cheers

Tuesday, 12 October 2010

How to count number of lines in a TextField

I was facing this dilema to correct a game were in the textfields the text can have 1, 2 or 3 lines. Depending on the number of lines I wanted to center the text vertically so that when it had only 1 line, it would append a new line "\n" before the text.

This only applies to normal dynamic textfields, not TFL. These have their own methods to center text both horizontally and vertically... much easier.

There's a property called numLines, but this only states that the chosen TextField will have an x number of lines that you specify, you can't use it to return the number of text lines that you see.

So you have to make another type of calculation, and the textfield must be multiline.

var myHeight:Number = myText.height; //store the height of the textfield
myText.multiline = true; //don't need to do this, if it is in the properties panel
myText.wordWrap = true; //same as above

myText.height = myHeight; // here is the trick, try removing this line
trace("DYNAMIC TEXTFIELD HAVE "+myText.maxScrollV+" LINES");

Cheers

Time lapse for FLVPlayback

This is one of those cases when the Adobe documentation is rare, or doesn't help much.

I had a hard time figuring out how to place a bar that would grow along with the playback of a movie in the FLVPlayback component.

First make a custom MovieClip with a rectangle (it can be another shape, but usually rectangles are best for these) and give it a name: myPlayhead

You must have already the FLVPlayback component on stage, with a given name. I will name it: myFLVplayback

For the script we will need to import a class to do this: VideoEvent. This class has several events you can use to get info from the FLVplayback when playing video (http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/VideoEvent.html)

import flash.video.VideoEvent;


//The movie doesn't start
myFLVPlayback.stop();


//Rewinds automatically if the video is stopped or it reaches the end.
//By default it's false
myFLVPlayback.autoRewind=true;


//Adds the listener for each time the playhead updates it's position

myFLVPlayback.addEventListener(VideoEvent.PLAYHEAD_UPDATE, videoHandler);


function videoHandler(evt:VideoEvent):void{
var totalSeconds:Number = myFLVPlayback.totalTime;
var elapsedSeconds:Number = myFLVPlayback.playheadTime;

var percent:Number=Math.round((elapsedSeconds/totalSeconds)*100);
        
        //The custom seekBar will change it's size according the the percentage
        //of the played movie
seekBt.progressMc.scaleX=percent;
}


Cheers

Custom controls for the FLVPlayback video component

This time I had to help a friend that needed to play some videos in a fancy interface.

The problem was that he didn't want the buttons that Flash provides for video playback, and wanted some flexibility towards mouse events, i.e., beeing able to hide or show the buttons with custom events or mouse events.

For now I will tell how I changed the controls.

First of all you need to make some custom MovieClips for the buttons. One MovieClip per button.

(this is valid for actionscripting the interface, or placing the components directly on stage)

Place the FLVplayback component in the stage and give it a name: myFlvplayback

Place the buttons where you want on the interface, and give them a name: playBt, pauseBt, stopBt,... and so on.

Now the script. You have to associate the buttons to the video component, stating what each button will do, like this:


myFlvplayback.playButton=playBt;
myFlvplayback.stopButton=stopBt;
myFlvplayback.seekBar=seekBt;
myFlvplayback.pauseButton=pauseBt;

That's it. If you run the movie, you'll see that this is enough to custom controls for this video component.

A further step is to make a custom interface with the all buttons inside a single MovieClip. Then you can make your custom autohide function with some MouseEvents.

Cheers

Thursday, 2 September 2010

Logical XOR

Flash doesn't have a logical XOR, only a bitwise XOR. That means that you can only do bitwise operations, or swap number and attribute the result to a variable.

Well I needed a Boolean XOR, like the one with Truth Tables that we know from logical programming. Well this little function takes care of this:

public function xor(lhs:Boolean, rhs:Boolean):Boolean {


return !( lhs && rhs ) && ( lhs || rhs );

}



Cheers,
Leonel

Wednesday, 1 September 2010

Fullscreen... and back

To get your stage into full screen you must do in two steps. The first is to set your stage display state in ActionScript. The other is to allow this scaling in the HTML page.

First of all, place a MovieClip in the stage, by code, or directly in the stage. Give it a instance name.
I will cal mine: fullScr

Associate with fullScr an event listener to catch a mouse event to execute the full screen:

fullScr.addEventListener(MouseEvent.CLICK, handleMouseClick);

Write the handleMouseClick function that will set the display state of the stage. This function will detect the current display state, and change it accordingly. If the display state is NORMAL, it will set it to FULLSCREEN. Otherwise it will be NORMAL again:


private function handleMouseClick(me:MouseEvent):void
{
   if (stage.displayState == StageDisplayState.NORMAL) {
     try{
        stage.displayState=StageDisplayState.FULL_SCREEN;
     }
     catch (e:SecurityError){
        //if you don't complete STEP TWO below, you will get this SecurityError
       trace("an error has occured. please modify the html file to allow    
       fullscreen mode");
     }
   }else {
  try{
       stage.displayState=StageDisplayState.NORMAL;
     }
     catch (e:SecurityError){
       //if you don't complete STEP TWO below, you will get this SecurityError
       trace("an error has occured. please modify the html file to allow 
       fullscreen mode");
     }
  }
}

If you have a video component like FLVPlayback, when you hit fullscreen, this component will take over the screen because it is on top of everything else. To prevent this add this line:

myPlayer.fullScreenTakeOver=false;

Cheers,
Leonel