Sunday, November 18, 2012

Creating EasyTooltip class: Part 17

Today we'll begin working on the ability to add dynamic content to tooltips.

By dynamic content I mean any visible object: a MovieClip, a Sprite, an instance of a class of your own, practically anything that can be put onto stage. To accomplish this, we'll add a new property to the TooltipStyle, as well as a new method.

Go to that class now and add a new variable called dynamicContent:

public var dynamicContent:Array;

Set it to an empty array in the constructor:

dynamicContent = [];

Now add a new method called addContent, with 3 parameters - content, x_pos and y_pos. In the function, add a new hash element to the dynamicContent array, which has 3 attributes - c, x and y. Set their values to content, x_pos and y_pos:

/**
 * Add an object to display in the tooltip as dynamic content.
 * @paramcontent Class of the object to add to the tooltip.
 * @paramx X coordinate of the object inside the tooltip.
 * @paramy Y coordinate of the object inside the tooltip.
 */

public function addContent(content:Class, x_pos:int, y_pos:int):void {
dynamicContent.push({c:content, x:x_pos, y:y_pos});
}

This is the function that the developer will use to add content to the tooltip using style. As you can see, the content object that is passed as the first parameter is a Class. In TooltipCursor, an instance of this class is created and displayed. This way the same style can be reused for multiple EasyTooltips.

Full TooltipStyle class code:

package com.kircode.EasyTooltip 
{
import flash.text.TextFormat;
/**
 * Used for visually styling tooltips.
 * @author Kirill Poletaev
 */
public class TooltipStyle 
{
public var backgroundRect:*;
public var backgroundStroke:*;
public var textAlpha:Number;
public var textFormat:TextFormat;
public var textPadding:TextPadding;
public var offsetX:int;
public var offsetY:int;
public var maxWidth:int;
public var minWidth:int;
public var maxHeight:int;
public var minHeight:int;
public var dynamicContent:Array;

public function TooltipStyle() 
{
backgroundRect = new SolidColorRect(0x222222, [0, 0, 0, 0], 1);
backgroundStroke = new SolidColorStroke(1, 0x0, 1);
textAlpha = 1;
textFormat = new TextFormat("Arial", 17, 0xffffff);
textPadding = new TextPadding(5, 5, 5, 5);
offsetX = 0;
offsetY = 0;
maxWidth = 0;
minWidth = 0;
maxHeight = 0;
minHeight = 0;
dynamicContent = [];
}

/**
 * Add an object to display in the tooltip as dynamic content.
 * @paramcontent Class of the object to add to the tooltip.
 * @paramx X coordinate of the object inside the tooltip.
 * @paramy Y coordinate of the object inside the tooltip.
 */

public function addContent(content:Class, x_pos:int, y_pos:int):void {
dynamicContent.push({c:content, x:x_pos, y:y_pos});
}

}

}

Now go to TooltipCursor class. Declare a content array:

private var content:Array;

Then go to setStyle() function and set the content value to an empty array.

Loop through all dynamicContent elements of the style, create instances of the provided classes, and push a hash object to the content array, which has 3 attributes - c, x and y, where c is the reference to the object (not class!) that is displayed, and x and y are coordinates of that object. Then add the object to the display list.

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

public function setStyle(st:TooltipStyle):void {
style = st;
content = [];
var i:int;
for (i = 0; i < style.dynamicContent.length; i++) {
var obj = new style.dynamicContent[i].c();
content.push({c:obj, x:style.dynamicContent[i].x, y:style.dynamicContent[i].y});
addChild(obj);
}
}

Go to the updateDisplay() function and add a loop that sets the position of the content:

var i:int;
for (i = 0; i < content.length; i++) {
content[i].c.x = actual_x + content[i].x;
content[i].c.y = actual_y + content[i].y;
}

Full TooltipCursor 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 = "";
private var content:Array;

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;
content = [];
var i:int;
for (i = 0; i < style.dynamicContent.length; i++) {
var obj = new style.dynamicContent[i].c();
content.push({c:obj, x:style.dynamicContent[i].x, y:style.dynamicContent[i].y});
addChild(obj);
}
}

/**
 * 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;

var i:int;
for (i = 0; i < content.length; i++) {
content[i].c.x = actual_x + content[i].x;
content[i].c.y = actual_y + content[i].y;
}
}

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; 
}
}
}

}

}

}

We now have some basic dynamic content functionality. To test it out, draw an icon graphic inside a MovieClip and give it a class path "myIcon".

Use the code below:

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

myStyle.addContent(myIcon, 5, 5);

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");

The results should look something like this:


No comments:

Post a Comment