package iTop { import flash.display.*; import flash.geom.*; import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFieldAutoSize; import flash.text.TextLineMetrics; import flash.display.BlendMode; import flash.utils.Timer; import flash.events.MouseEvent; public class ToolTip extends Sprite { private var _tip:String; // You'll need this for proper text formatting private var _tf:TextField = new TextField(); private var _format:TextFormat = new TextFormat(); private static const ROUND:Number = 10; private static const HEIGHT:Number = 25; private static const FONT_SIZE:uint = 12; private static const FONT:String = 'Arial'; private static const PADDING:Number = 5; private static const MIN_ALPHA:Number = 0.0; private static const ALPHA_INC:Number = 0.1; private static const MAX_ALPHA:Number = 1; private static const REFRESH:Number = (MAX_ALPHA - MIN_ALPHA) / ALPHA_INC; private static const APPEAR_TIMEOUT = 1000; // ms // For appearence, fading in and out public var timer:Timer; public function ToolTip( tip:String ) { // Hold onto the tip for posterity _tip = tip; // This ensures the textfield inherits this class's // alpha property. Very important because otherwise tf // would always have an alpha of 1 meaning it will always be visible this.blendMode = BlendMode.LAYER; _format.size = FONT_SIZE; _format.font = FONT; // Make sure the text behaves and looks // the way text on a button should _tf.defaultTextFormat = _format; // Always call defaultTextFormat before setting text otherwise // the text doesn't use the formatting defined in tf _tf.autoSize = TextFieldAutoSize.LEFT; // You have to set autoSize to TextFieldAutoSize.LEFT // for box.textWidth to be accurate _tf.multiline = true; _tf.htmlText = tip; _tf.selectable = false; _tf.x += PADDING; _tf.y += PADDING; addChild( _tf ); // Draw the background graphics.beginFill( 0xEEEE99, 0.95 ); graphics.drawRoundRect( 0, 0, _tf.textWidth+PADDING*4, _tf.textHeight+PADDING*4, ROUND ); graphics.endFill(); this.alpha = MIN_ALPHA; } // You have to call this after // the tooltip has been added to the // display list public function start():void { this.parent.addEventListener( MouseEvent.MOUSE_OVER, mouse_over ); } public function mouse_over( e:MouseEvent ):void { // Make the tooltip appear smoothly after a delay if (this.timer != null) { this.timer.stop(); } this.timer = new Timer( APPEAR_TIMEOUT, 1 ); this.timer.addEventListener( "timer", appear ); this.timer.start(); this.parent.addEventListener( MouseEvent.MOUSE_OUT, mouse_out ); } public function mouse_out( e:MouseEvent ):void { var fadeSpeed:Number = 500 / REFRESH; if (this.timer != null) { this.timer.stop(); } this.timer = new Timer( fadeSpeed, REFRESH ); this.timer.addEventListener( "timer", fadeOut ); this.timer.start(); this.parent.removeEventListener( MouseEvent.MOUSE_OUT, mouse_out ); } private function appear(i:uint):void { // The delay has elapsed, show (smoothly) the tooltip // Make sure that the tooltip always appears at se same scale 1:1 even // if the whole scene is zoomed out scaleX = 1 / this.parent.parent.scaleX; scaleY = 1 / this.parent.parent.scaleY; if (this.timer != null) { this.timer.stop(); } // Reuse the time for the fadeIn this.parent.setChildIndex( this, this.parent.numChildren-1 ) // Move the tool tip to the top! var fadeSpeed:Number = 500 / REFRESH; this.alpha = MIN_ALPHA; if (this.timer != null) { this.timer.stop(); } this.timer = new Timer( fadeSpeed, REFRESH ); this.timer.addEventListener( "timer", fadeIn ); this.timer.start(); this.parent.addEventListener( MouseEvent.MOUSE_OUT, mouse_out ); } private function fadeIn( i:uint ):void { if (this.alpha < (1.0 - ALPHA_INC)) { this.alpha += ALPHA_INC; } else { this.alpha = 1.0; } //trace("++ Tooltip alpha: "+this.alpha+" ALPHA_INC:"+ALPHA_INC); } private function fadeOut( i:uint ):void { if (this.alpha > ALPHA_INC) { this.alpha -= ALPHA_INC; } else { this.alpha = 0.0; } //trace("-- Tooltip alpha: "+this.alpha+" ALPHA_INC:"+ALPHA_INC); } } }