I was glad to see the latest in Lee Brimelow’s great series of video Flash tutorials, this one on making tooltips in Flash. I’d been meaning to implement tooltips in my current project for a while, and this got me going. But you know I always prefer to do it in code that I can reuse anywhere, and not depend on library assets if I can help it. And tooltip is a prime candidate for implementation with a Singleton class, so…
import ascb.util.Proxy;
class com.nodename.utils.ToolTip
{
static var version:String = "$Id: ToolTip.as,v 1.9 2006/03/26 18:14:15 ashaw Exp $";
public static function setBoxSize(wd:Number, ht:Number):Void
{
ToolTip._boxWidth = wd;
ToolTip._boxHeight = ht;
}
public static function setPointSize(ps:Number):Void
{
ToolTip._pointSize = ps;
}
/*
*
* @function create
* @param tipTarget the object over which the tooltip is to be shown:
* MovieClip, MCComposite, or Button
* @param tip the text to be displayed in the ToolTip
*
*/
public static function create(tipTarget, tip:String):Void
{
tipTarget.onRollOver = Proxy.create(ToolTip, ToolTip.showToolTip, tip);
tipTarget.onRollOut = tipTarget.onDragOut = ToolTip.hideToolTip;
}
/////////////////////////////////////////
// //
// End of public interface //
// //
/////////////////////////////////////////
private static var theOnlyToolTip:ToolTip;
private static function showToolTip(tip:String):Void
{
if (theOnlyToolTip == undefined)
{
theOnlyToolTip = new ToolTip();
}
theOnlyToolTip.p_showToolTip(tip);
}
private static function hideToolTip():Void
{
if (theOnlyToolTip == undefined)
{
theOnlyToolTip = new ToolTip();
}
theOnlyToolTip.p_hideToolTip();
}
private var _mc:MovieClip;
private var _tf:TextField;
private var _tFormat:TextFormat;
private static var _boxWidth:Number = 150;
private static var _boxHeight:Number = 50;
private static var _pointSize:Number = 10;
private var _tailLeft:Number; // distance from left edge of box to left edge of tail
private var _tailWidth:Number;
private var _tailHeight:Number;
private var _tailTipOffset:Number; // tip of tail is this far above registration point
private var _textSideMargin:Number;
private var topY:Number;
private var leftX:Number;
private function ToolTip()
{
_tailLeft = .40 * ToolTip._boxHeight;
_tailWidth = .40 * ToolTip._boxHeight;
_tailHeight = .60 * ToolTip._boxHeight;
_tailTipOffset = 5;
_textSideMargin = 5;
var trueParent:MovieClip = _level0; // it has to live somewhere...
this._mc = trueParent.createEmptyMovieClip("nodenameToolTip", trueParent.getNextHighestDepth());
this._mc._visible = false;
leftX = -this._tailLeft;
topY = -ToolTip._boxHeight - this._tailHeight - this._tailTipOffset;
this.draw(leftX, topY, ToolTip._boxWidth, ToolTip._boxHeight, this._tailWidth, this._tailTipOffset);
this.makeTextField(leftX, topY, ToolTip._boxWidth, ToolTip._boxHeight);
}
private function draw(leftX:Number, topY:Number, boxWidth:Number, boxHeight:Number,
tailWidth:Number, tailTipOffset:Number):Void
{
// TODO: make rounded corners
var rightX:Number = leftX + boxWidth;
var bottomY:Number = topY + boxHeight;
with (this._mc)
{
moveTo(leftX, topY);
lineStyle(1, 0x000000, 100); // black
beginGradientFill(
"linear",
[0xfff3d9, 0xfffbf2], // colors
[100, 100], // alphas
[0, 255], // ratios
{
matrixType:"box",
x: leftX, y: topY,
w: boxWidth, h: boxHeight,
r: Math.PI/2 // 90 degrees: vertical gradient
}
);
lineTo(rightX, topY);
lineTo(rightX, bottomY);
lineTo(tailWidth, bottomY);
lineTo(0, -tailTipOffset); // tip of tail
lineTo(0, bottomY);
lineTo(leftX, bottomY);
lineTo(leftX, topY);
endFill();
}
}
private function makeTextField(leftX:Number, topY:Number, boxWidth:Number, boxHeight:Number):Void
{
this._mc.createTextField("_tf", this._mc.getNextHighestDepth(),
leftX, topY, boxWidth, boxHeight);
this._tf = this._mc._tf;
this._tFormat = new TextFormat("_sans", ToolTip._pointSize, 0×000000);
this._tFormat.align = "center";
this._tFormat.leftMargin = this._tFormat.rightMargin = this._textSideMargin;
this._tf.setNewTextFormat(this._tFormat);
this._tf.wordWrap = true;
this._tf.autoSize = "none";
}
private var _toolTipIntervalID:Number;
private var _toolTipDelay:Number = 500; // milliseconds
private function p_showToolTip(tip:String):Void
{
this._toolTipIntervalID = setInterval(this, "reallyShowToolTip", this._toolTipDelay, tip);
}
private function reallyShowToolTip(tip:String):Void
{
clearInterval(this._toolTipIntervalID);
this._tf.text = tip;
updateToolTip();
this._mc._visible = true;
this._mc.onMouseMove = Proxy.create(this, updateToolTip);
}
private function updateToolTip():Void
{
setFlip();
this._mc._x = this._mc._parent._xmouse;
this._mc._y = this._mc._parent._ymouse;
updateAfterEvent();
}
public function setFlip():Void
{
var loc:Object = {x: this._mc._xmouse, y: this._mc._ymouse};
this._mc.localToGlobal(loc);
if (loc.y + topY < 5)
{
flipY();
}
else
{
unflipY();
}
if (loc.x + leftX + ToolTip._boxWidth > Stage.width - 5)
{
flipX();
}
else
{
unflipX();
}
}
private function flipY():Void
{
this._mc._yscale = -100;
this._tf._yscale = -100;
this._tf._y = topY + ToolTip._boxHeight;
}
private function unflipY():Void
{
this._mc._yscale = 100;
this._tf._yscale = 100;
this._tf._y = topY;
}
private function flipX():Void
{
this._mc._xscale = -100;
this._tf._xscale = -100;
this._tf._x = leftX + ToolTip._boxWidth;
}
private function unflipX():Void
{
this._mc._xscale = 100;
this._tf._xscale = 100;
this._tf._x = leftX;
}
private function p_hideToolTip():Void
{
clearInterval(this._toolTipIntervalID);
this._mc._visible = false;
delete this._mc.onMouseMove;
}
}

