Monday, November 19, 2012

Creating EasyTooltip class: Part 18

In this tutorial we will improve our dynamic content feature and add the ability to set tooltip filters using styles.

The setStyle() function of TooltipCursor class, which sets the style and adds the content to the tooltip, can be called multiple times by the developer. Right now the code would add the new dynamic content without removing the old one. This leads to unneeded elements being displayed in the tooltip, so go to TooltipCursor's setStyle() function right now and add a loop that deletes each content object before adding the new stuff.

Moreover, add a line that sets the filters property of the cursor to style.filters.

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

public function setStyle(st:TooltipStyle):void {
style = st;
var i:int;
for (i = content.length-1; i >= 0; i--) {
content[i].c.parent.removeChild(content[i].c);
content[i].c = null;
content.splice(i, 1);
}

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);
}
this.filters = style.filters;
}

We need to move the line that sets content to an empty array to the constructor:

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;
content = [];
}

Full class code so far:

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;
content = [];
}

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

public function setStyle(st:TooltipStyle):void {
style = st;
var i:int;
for (i = content.length-1; i >= 0; i--) {
content[i].c.parent.removeChild(content[i].c);
content[i].c = null;
content.splice(i, 1);
}

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);
}
this.filters = style.filters;
}

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

}

}

}

Go to TooltipStyle class and update it by declaring a new variable filters.

public var filters:Array;

Set it to an array which contains 1 DropShadow filter by default:

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 = [];
filters = [new DropShadowFilter(4, 45, 0, 0.5, 4, 4, 1, 2)];
}

Full class code:

package com.kircode.EasyTooltip 
{
import flash.filters.DropShadowFilter;
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 var filters: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 = [];
filters = [new DropShadowFilter(4, 45, 0, 0.5, 4, 4, 1, 2)];
}

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

}

}

That's all for today.

Thanks for reading!

Here's an example code:

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

And the results:


No comments:

Post a Comment