Saturday, November 17, 2012

Creating EasyTooltip class: Part 16

Today we'll add the ability to create bitmap fills and strokes for our tooltips.

First, create 2 new class files - BitmapRect.as and BitmapStroke.as. These are similar to the classes of the same name in the AdvAlert library.

BitmapRect.as code:

package com.kircode.EasyTooltip 
{
import flash.display.BitmapData;
import flash.geom.Matrix;
/**
 * ...
 * @author Kirill Poletaev
 */
public class BitmapRect
{
public var _bitmap:BitmapData;
public var _matrix:Matrix;
public var _repeat:Boolean;
public var _smooth:Boolean;
public var _radius:Array;

/**
 * Create a rectangle filled with bitmap. Has the same parameters as beginBitmapFill(), plus lineThickness, lineColor, lineAlpha and cornerRadius.
 * @parambitmap BitmapData to be used to fill the rectangle.
 * @parammatrix Matrix object for transformation.
 * @paramrepeat Repeat the bitmap when filling.
 * @paramsmooth Smoothen the bitmap.
 * @paramcornerRadius Radius of the corners of the box - top left, top right, bottom left, bottom right.
 */

public function BitmapRect(bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false, cornerRadius:Array = null) 
{
if (cornerRadius == null) cornerRadius = [10, 10, 0, 0];
_bitmap = bitmap;
_matrix = matrix;
_repeat = repeat;
_smooth = smooth;
_radius = cornerRadius;
}

}

}

BitmapStroke.as code:

package com.kircode.EasyTooltip 
{
import flash.display.BitmapData;
import flash.geom.Matrix;
/**
 * ...
 * @author Kirill Poletaev
 */
public class BitmapStroke
{
public var _lineThickness:Number;
public var _bitmap:BitmapData;
public var _matrix:Matrix;
public var _repeat:Boolean;
public var _smooth:Boolean;

/**
 * Create a bitmap filled line stroke. Uses same parameters as lineBitmapStyle() + lineThickness.
 * @paramlineThickness Thickness of the line stroke.
 * @parambitmap BitmapData to be used to fill the rectangle.
 * @parammatrix Matrix object for transformation.
 * @paramrepeat Repeat the bitmap when filling.
 * @paramsmooth Smoothen the bitmap.
 */

public function BitmapStroke(lineThickness:Number, bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false) 
{
_lineThickness = lineThickness;
_bitmap = bitmap;
_matrix = matrix;
_repeat = repeat;
_smooth = smooth;
}

}

}

Go to TooltipCursor.as, find the updateDisplay() function. Create 2 new if..statements here.

The first one checks if style.backgroundStroke is an object of class BitmapStroke. Base this if..statement off the one that checks if the object is an instance of GradientColorStroke, just change lineGradientStyle() to lineBitmapStyle() and use the approporiate values:

if (style.backgroundStroke is BitmapStroke) {
if(style.backgroundStroke._matrix){
style.backgroundStroke._matrix.tx = actual_x;
style.backgroundStroke._matrix.ty = actual_y;
}
background.graphics.lineStyle(style.backgroundStroke._lineThickness);
background.graphics.lineBitmapStyle(style.backgroundStroke._bitmap, style.backgroundStroke._matrix, style.backgroundStroke._repeat, style.backgroundStroke._smooth);
}

The second if...statement checks if backgroundRect is an instance of BitmapRect class. Base this one on the if...statement that checks if backgroundRect is an object of GradientColorRect class. Change beginGradientFill() to beginBitmapFill() and use the new values:

if (style.backgroundRect is BitmapRect) {
if(style.backgroundRect._matrix){
style.backgroundRect._matrix.tx = actual_x;
style.backgroundRect._matrix.ty = actual_y;
}
background.graphics.beginBitmapFill(style.backgroundRect._bitmap, style.backgroundRect._matrix, style.backgroundRect._repeat, style.backgroundRect._smooth);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}

Full class code:

package com.kircode.EasyTooltip 
{
import flash.display.MovieClip;
import flash.display.Shape;
import flash.text.TextField;
import flash.text.TextFormat;
/**
 * The cursor that follows the mouse (if not set otherwise) and displays each tooltip.
 * @author Kirill Poletaev
 */
public class TooltipCursor extends MovieClip
{

public var txt:TextField;
private var style:TooltipStyle;
private var background:Shape;
private var w:int;
private var h:int;
private var actual_x:int;
private var actual_y:int;
private var parentW:int;
private var parentH:int;
private var direction:String = "";

public function TooltipCursor(pW:int, pH:int) 
{
parentW = pW;
parentH = pH;
txt = new TextField();
txt.multiline = true;
background = new Shape();
addChild(background);
addChild(txt);
txt.width = 1;
txt.height = 1;
}

/**
 * Set style of the tooltips.
 * @paramst TooltipStyle object to apply.
 */

public function setStyle(st:TooltipStyle):void {
style = st;
}

/**
 * Change the text value of the tooltip.
 * @parammessage The new text value.
 */

public function setText(message:String):void {
txt.text = message;
txt.setTextFormat(style.textFormat);
updateSize();
updateDisplay();
}

private function updateDisplay():void {
background.graphics.clear();

if (style.backgroundStroke is SolidColorStroke) {
background.graphics.lineStyle(style.backgroundStroke._lineThickness, style.backgroundStroke._lineColor, style.backgroundStroke._lineAlpha);
}

if (style.backgroundStroke is GradientColorStroke) {
if(style.backgroundStroke._matrix){
style.backgroundStroke._matrix.tx = actual_x;
style.backgroundStroke._matrix.ty = actual_y;
}
background.graphics.lineStyle(style.backgroundStroke._lineThickness);
background.graphics.lineGradientStyle(style.backgroundStroke._gradientType, style.backgroundStroke._colors, style.backgroundStroke._alphas, style.backgroundStroke._ratios, style.backgroundStroke._matrix, style.backgroundStroke._spreadMethod, style.backgroundStroke._interpolationMethod, style.backgroundStroke._focalPointRatio);
}

if (style.backgroundStroke is BitmapStroke) {
if(style.backgroundStroke._matrix){
style.backgroundStroke._matrix.tx = actual_x;
style.backgroundStroke._matrix.ty = actual_y;
}
background.graphics.lineStyle(style.backgroundStroke._lineThickness);
background.graphics.lineBitmapStyle(style.backgroundStroke._bitmap, style.backgroundStroke._matrix, style.backgroundStroke._repeat, style.backgroundStroke._smooth);
}

if (style.backgroundRect is SolidColorRect) {
background.graphics.beginFill(style.backgroundRect._backgroundColor, style.backgroundRect._alpha);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}

if (style.backgroundRect is GradientColorRect) {
if(style.backgroundRect._matrix){
style.backgroundRect._matrix.tx = actual_x;
style.backgroundRect._matrix.ty = actual_y;
}
background.graphics.beginGradientFill(style.backgroundRect._gradientType, style.backgroundRect._colors, style.backgroundRect._alphas, style.backgroundRect._ratios, style.backgroundRect._matrix, style.backgroundRect._spreadMethod, style.backgroundRect._interpolationMethod, style.backgroundRect._focalPointRatio);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}

if (style.backgroundRect is BitmapRect) {
if(style.backgroundRect._matrix){
style.backgroundRect._matrix.tx = actual_x;
style.backgroundRect._matrix.ty = actual_y;
}
background.graphics.beginBitmapFill(style.backgroundRect._bitmap, style.backgroundRect._matrix, style.backgroundRect._repeat, style.backgroundRect._smooth);
background.graphics.drawRoundRectComplex(actual_x, actual_y, w, h, style.backgroundRect._radius[0], style.backgroundRect._radius[1], style.backgroundRect._radius[2], style.backgroundRect._radius[3]);
background.graphics.endFill();
}

txt.width = w - style.textPadding.left - style.textPadding.right;
txt.height = h - style.textPadding.top - style.textPadding.bottom;
txt.x = actual_x + style.textPadding.left;
txt.y = actual_y + style.textPadding.top;
}

private function updateSize():void {
if (style.maxWidth == 0) style.maxWidth = parentW;
if (style.maxHeight == 0) style.maxHeight = parentH;
txt.wordWrap = true;
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
if (w > style.maxWidth) w = style.maxWidth;
if (h > style.maxHeight) h = style.maxHeight;
if (w < style.minWidth) w = style.minWidth;
if (h < style.minHeight) h = style.minHeight;

// calculate best direction
if (this.y <= h-style.offsetY) { 
direction = "bottom"; 
actual_y = -style.offsetY;
} else
if (this.y > h-style.offsetY) { 
direction = "top";
actual_y = -h + style.offsetY;
}

if (this.x <= parentW * 0.5) { 
direction += "right"; 
actual_x = - style.offsetX;
} else
if (this.x > parentW * 0.5) { 
direction += "left";
actual_x = -w + style.offsetX;
}

// If sticks out on the right:
if(direction == "topright" || direction == "bottomright"){
// if tooltip sticks out of border - calculate shortened width to fit the content
if (this.x + actual_x + w > parentW) {
txt.wordWrap = true;
w = parentW - this.x - actual_x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
if (w > style.maxWidth) w = style.maxWidth;
if (h > style.maxHeight) h = style.maxHeight;
if (w < style.minWidth) {
w = style.minWidth;
this.x = parentW - w + style.offsetX;
}
if (h < style.minHeight) h = style.minHeight;
} else {
// if doesn't stick out, keep adding 1 pixel to the width until as much text is seen as possible
while (this.x + actual_x + w < parentW && w < style.maxWidth && w >= style.minWidth) {
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right && w >= style.minWidth && w < style.maxWidth) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
if (w < style.minWidth) {
w = style.minWidth;
}
break;
}
txt.wordWrap = true;
}
}
}

// If sticks out on the left:
if(direction == "topleft" || direction == "bottomleft"){
if (this.x + actual_x <= 0) {
txt.wordWrap = true;
actual_x = -this.x;
w = this.x + style.offsetX;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
if (w > style.maxWidth) w = style.maxWidth;
if (h > style.maxHeight) h = style.maxHeight;
if (w < style.minWidth) w = style.minWidth;
if (h < style.minHeight) h = style.minHeight;
} else {
// if doesn't stick out, keep adding 1 pixel to the width (and substracting it from actual_x) until as much text is seen as possible
while (this.x + actual_x > 0 && w < style.maxWidth && w >= style.minWidth) {
actual_x -= 1;
w += 1;
// try turning off wordwrap and see if it still fits (as one line)
txt.wordWrap = false;
if (w > txt.textWidth + 4 + style.textPadding.left + style.textPadding.right && w >= style.minWidth && w <= style.maxWidth) {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
if (w < style.minWidth) {
w = style.minWidth;
}
break;
}
txt.wordWrap = true; 
}
}
}

}

}

}

Using bitmap strokes and fills is now as easy as it is to use gradients. In this example, I create 2 perlin noise BitmapDatas and set them as stroke and fill of the tooltip:

var myStyle:TooltipStyle = new TooltipStyle();
myStyle.minWidth = 240;
myStyle.maxWidth = 0;
myStyle.offsetX = -10;
myStyle.offsetY = -10;

var myBitmap:BitmapData = new BitmapData(200, 100, false, 0x000000);
myBitmap.perlinNoise(200, 100, 3, 7, true, true);

var myBitmap2:BitmapData = new BitmapData(200, 100, false, 0x000000);
myBitmap2.perlinNoise(100, 100, 3, 11, true, true);

myStyle.backgroundRect = new BitmapRect(myBitmap, new Matrix(), true, true, [10, 10, 10, 10]);
myStyle.backgroundStroke = new BitmapStroke(2, myBitmap2, new Matrix(), true, true);

tooltip = new EasyTooltip(stage, stage.stageWidth, stage.stageHeight, 0);
tooltip.setStyle(myStyle);
tooltip.addListener(object1, "Test test test test test test test test test test test test test test test");

Thanks for reading!

The results:


No comments:

Post a Comment