Showing posts with label class. Show all posts
Showing posts with label class. Show all posts

Wednesday, February 4, 2015

Creating Advanced Alert Window class Part 7

In this part we will remake the way the user implements skins for alert windows.

Right now to apply a custom alert window skin the user has to pass a reference to an AdvAlertSkin object to the alert() method each time an alert is called. This is unconvenient, so we are going to add new ways to implement skins.

The first way will be to pass a skin value through the constructor of AdvAlertManager. The parameter is optional, default skin is used if nothing is specified here.

The second way will be to use AdvAlertManagers setSkin() method, which sets the skin of all alert windows created after setSkin() being called.

Lets implement those features now.

Go to AdvAlertManager.as and declare a new variable "skin":

private var skin:AdvAlertSkin;

Go to the constructor and add a new optional parameter, windowSkin, set default value to null.

Then check if the value is null, and if so - create a new AdvAlertSkin() and apply it to skin variable. Otherwise, apply the passed AdvAlertSkin object to our skin variable:

/**
* AdvAlertManager constructor.
* @paramdefaultWindowContainer Parent container of alert windows.
* @paramparentWidth Containers width.
* @paramparentHeight Containers height.
*/

public function AdvAlertManager(defaultWindowContainer:DisplayObjectContainer, parentWidth:int, parentHeight:int, windowSkin:AdvAlertSkin = null)
{
trace(": AdvAlertManager instance created.");
skin = windowSkin;
if (skin == null) skin = new AdvAlertSkin();
defaultContainer = defaultWindowContainer;
pWidth = parentWidth;
pHeight = parentHeight;
windows = [];
}

Now create a new public function called setSkin(), which simply receives a skin object and applies it to "skin":

/**
* Set skin of all future created alert windows.
* @paramwindowSkin Reference to a skin object.
*/

public function setSkin(windowSkin:AdvAlertSkin):void {
skin = windowSkin

Remove the skin parameter and code related to it from alert():

/**
* Create an alert window.
* @paramtext Text value of the alert window.
* @paramtitle Title value of the alert window.
* @paramwidth (Optional) Width of the alert window. 300 by default.
* @paramheight (Optional) Height of the alert window. 200 by default.
* @paramposition (Optional) Coordinates of top-left corner of the alert window. If not specified - the window is centered.
*/

public function alert(text:String, title:String = "", width:int = 300, height:int = 200, position:Point = null):void {
if (position == null) position = new Point((pWidth / 2) - (width / 2), (pHeight / 2) - (height / 2));
var w:AdvAlertWindow = new AdvAlertWindow(text, title, width, height, position, skin);
windows.push(w);
defaultContainer.addChild(w);

trace("Message: " + text);
}

Full AdvAlertManager.as code:

package com.kircode.AdvAlert 
{
import flash.display.DisplayObjectContainer;
import flash.display.MovieClip;
import flash.geom.Point;
/**
* Advanced Alert window manager.
* @author Kirill Poletaev
*/
public class AdvAlertManager
{
private var windows:Array;
private var defaultContainer:DisplayObjectContainer;
private var pWidth:int;
private var pHeight:int;
private var skin:AdvAlertSkin;

/**
* AdvAlertManager constructor.
* @paramdefaultWindowContainer Parent container of alert windows.
* @paramparentWidth Containers width.
* @paramparentHeight Containers height.
*/

public function AdvAlertManager(defaultWindowContainer:DisplayObjectContainer, parentWidth:int, parentHeight:int, windowSkin:AdvAlertSkin = null)
{
trace(": AdvAlertManager instance created.");
skin = windowSkin;
if (skin == null) skin = new AdvAlertSkin();
defaultContainer = defaultWindowContainer;
pWidth = parentWidth;
pHeight = parentHeight;
windows = [];
}

/**
* Set skin of all future created alert windows.
* @paramwindowSkin Reference to a skin object.
*/

public function setSkin(windowSkin:AdvAlertSkin):void {
skin = windowSkin;
}

/**
* Create an alert window.
* @paramtext Text value of the alert window.
* @paramtitle Title value of the alert window.
* @paramwidth (Optional) Width of the alert window. 300 by default.
* @paramheight (Optional) Height of the alert window. 200 by default.
* @paramposition (Optional) Coordinates of top-left corner of the alert window. If not specified - the window is centered.
*/

public function alert(text:String, title:String = "", width:int = 300, height:int = 200, position:Point = null):void {
if (position == null) position = new Point((pWidth / 2) - (width / 2), (pHeight / 2) - (height / 2));
var w:AdvAlertWindow = new AdvAlertWindow(text, title, width, height, position, skin);
windows.push(w);
defaultContainer.addChild(w);

trace("Message: " + text);
}

}

}

Go to main.as.

Here, there are now 3 ways to set a skin.

The first way is to use the default skin, by simply specifying nothing and alerting a window:

// Default skin:
AlertManager = new AdvAlertManager(this, stage.stageWidth, stage.stageHeight);
AlertManager.alert("Text message.", "Default skin");

The second way is to pass a custom skin through the constructor of AdvAlertManager:

// Create custom skin:
var mySkin:AdvAlertSkin = new AdvAlertSkin();
mySkin.bgRect = new SolidColorRect(0xff8888);

// Apply custom skin (way 1:)
AlertManager = new AdvAlertManager(this, stage.stageWidth, stage.stageHeight, mySkin);
AlertManager.alert("Text message.", "Custom skin - way 1");

The third way is to pass nothing through the constructor, but call setSkin() to apply a custom skin:

// Create custom skin:
var mySkin:AdvAlertSkin = new AdvAlertSkin();
mySkin.bgRect = new SolidColorRect(0xff8888);

// Apply custom skin (way 2:)
AlertManager = new AdvAlertManager(this, stage.stageWidth, stage.stageHeight);
AlertManager.setSkin(mySkin);
AlertManager.alert("Text message.", "Custom skin - way 2");

And thats all for today.

Thanks for reading!
Read more »

Creating Advanced Alert Window class Part 17

In this tutorial well add labels to the buttons, add the ability to set their width/height and rework the algorithm that positions the buttons.

Start by opening AdvAlertButton.as class and declaring 2 new variables - textField and txt:

private var textField:TextField;
private var txt;

In the constructor, receive 3 parameters (2 optional): label, width, height. Apply width, height and label values to w, h and txt variables. Set textField to a new TextField object, add it to container:

public function AdvAlertButton(label:String, width:Number = 80, height:Number = 30) 
{
w = width;
h = height;
txt = label;
textField = new TextField();
addChild(textField);

updateDraw();
}

In the updateDraw() function add code that sets textFields width, height, selectable and text variables values. Also temporarily set textColor to white.

public function updateDraw():void {
this.graphics.clear();
// draw bg
this.graphics.beginFill(0x3333aa, 1);
this.graphics.drawRect(0, 0, w, h);

// text field
textField.width = w;
textField.height = h;
textField.textColor = 0xffffff;
textField.text = txt;
textField.selectable = false;
}

Full AdvAlertButton class:

package com.kircode.AdvAlert 
{
import flash.display.MovieClip;
import flash.text.TextField;

/**
* Advanced Alert window object.
* @author Kirill Poletaev
*/
public class AdvAlertButton extends MovieClip
{

public var w:Number;
public var h:Number;
private var textField:TextField;
private var txt;

/**
* Button object placed in the alert window.
* @paramlabel Text label of the button.
* @paramwidth Width of the button.
* @paramheight Height of the button.
*/

public function AdvAlertButton(label:String, width:Number = 80, height:Number = 30)
{
w = width;
h = height;
txt = label;
textField = new TextField();
addChild(textField);

updateDraw();
}

public function updateDraw():void {
this.graphics.clear();
// draw bg
this.graphics.beginFill(0x3333aa, 1);
this.graphics.drawRect(0, 0, w, h);

// text field
textField.width = w;
textField.height = h;
textField.textColor = 0xffffff;
textField.text = txt;
textField.selectable = false;
}


}

}

Go to main.as, add 3 AdvAlertButtons to the button array of an alert window as an example. Set the middle ones width to something other than default value:

AlertManager = new AdvAlertManager(this, stage.stageWidth, stage.stageHeight);
AlertManager.alert("This is an alert window with the default skin.", "Example alert!", [new AdvAlertButton("OK"), new AdvAlertButton("Cancel", 60), new AdvAlertButton("Back")]);

Go to AdvAlertWindow.as and find the piece of code in updateDraw() function that is used to position the buttons in the alert window. Well rewrite this code, because right now it assumes that each button has the same width and height.

Declare a variable xCoord before the loop, check if buttons array has any elements in it, and if so - set the value to the coordinate of the left button:

var xCoord:Number;
if (buttons.length > 0) xCoord = pos.x + w - buttons[0].w - buttonbarPadding.right;

Then we loop through all the elements and increase the xCoord value with the interval and each buttons width (if i is greater than 0):

for (var i:int = 0; i < buttons.length; i++) {
if (i > 0) xCoord -= buttons[i].w + buttonInterval;
buttons[i].x = xCoord;
buttons[i].y = pos.y + h - buttons[i].h - buttonbarPadding.bottom;
}

Full AdvAlertWindow.as code:

package com.kircode.AdvAlert 
{
import flash.display.MovieClip;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.display.GradientType;

/**
* Advanced Alert window object.
* @author Kirill Poletaev
*/
public class AdvAlertWindow extends MovieClip
{
private var t:String;
private var tt:String;
private var w:int;
private var h:int;
private var pos:Point;
private var buttons:Array;

private var textField:TextField;
private var titleField:TextField;

private var textPadding:TextPadding;
private var headerPadding:TextPadding;
private var titlePadding:TextPadding;
private var headerHeight:Number;
private var buttonbarPadding:TextPadding;
private var buttonbarHeight:Number;
private var titleFormat:TextFormat;
private var textFormat:TextFormat;
private var selectable:Boolean;
private var headerRect:*;
private var bgRect:*;
private var headerStroke:*;
private var bgStroke:*;
private var skinFilters:Array;
private var buttonInterval:Number;

public function AdvAlertWindow(pt:String, ptt:String, pw:int, ph:int, ppos:Point, sk:AdvAlertSkin, bt:Array)
{
t = pt;
tt = ptt;
w = pw;
h = ph;
pos = ppos;
buttons = bt;

setSkin(sk);

textField = new TextField();
addChild(textField);

titleField = new TextField();
addChild(titleField);

for (var i:int = 0; i < buttons.length; i++) {
addChild(buttons[i]);
}

updateDraw();
}

public function setSkin(skin:AdvAlertSkin):void {
textPadding = skin.textPadding;
headerPadding = skin.headerPadding;
titlePadding = skin.titlePadding;
headerHeight = skin.headerHeight;
titleFormat = skin.titleFormat;
textFormat = skin.textFormat;
selectable = skin.selectable;
bgRect = skin.bgRect;
headerRect = skin.headerRect;
bgStroke = skin.bgStroke;
headerStroke = skin.headerStroke;
skinFilters = skin.filters;
buttonbarHeight = skin.buttonbarHeight;
buttonbarPadding = skin.buttonbarPadding;
buttonInterval = skin.buttonInterval;
}

public function updateDraw():void {
this.graphics.clear();
// filters
this.filters = skinFilters;

// bg stroke
if (bgStroke is SolidColorStroke) {
this.graphics.lineStyle(bgStroke._lineThickness, bgStroke._lineColor, bgStroke._lineAlpha);
}
if (bgStroke is GradientColorStroke) {
this.graphics.lineStyle(bgStroke._lineThickness);
this.graphics.lineGradientStyle(bgStroke._gradientType, bgStroke._colors, bgStroke._alphas, bgStroke._ratios, bgStroke._matrix, bgStroke._spreadMethod, bgStroke._interpolationMethod, bgStroke._focalPointRatio);
}
if (bgStroke is BitmapStroke) {
this.graphics.lineStyle(bgStroke._lineThickness);
this.graphics.lineBitmapStyle(bgStroke._bitmap, bgStroke._matrix, bgStroke._repeat, bgStroke._smooth);
}

// bg fill
if (bgRect is SolidColorRect) this.graphics.beginFill(bgRect._backgroundColor, bgRect._alpha);
if (bgRect is GradientColorRect) this.graphics.beginGradientFill(bgRect._gradientType, bgRect._colors, bgRect._alphas, bgRect._ratios, bgRect._matrix, bgRect._spreadMethod, bgRect._interpolationMethod, bgRect._focalPointRatio);
if (bgRect is BitmapRect) this.graphics.beginBitmapFill(bgRect._bitmap, bgRect._matrix, bgRect._repeat, bgRect._smooth);

this.graphics.drawRoundRectComplex(pos.x, pos.y, w, h,
bgRect._radius[0], bgRect._radius[1], bgRect._radius[2], bgRect._radius[3]);
this.graphics.endFill();

// header stroke
if (headerStroke is SolidColorStroke) {
this.graphics.lineStyle(headerStroke._lineThickness, headerStroke._lineColor, headerStroke._lineAlpha);
}
if (headerStroke is GradientColorStroke) {
this.graphics.lineStyle(headerStroke._lineThickness);
this.graphics.lineGradientStyle(headerStroke._gradientType, headerStroke._colors, headerStroke._alphas, headerStroke._ratios, headerStroke._matrix, headerStroke._spreadMethod, headerStroke._interpolationMethod, headerStroke._focalPointRatio);
}
if (headerStroke is BitmapStroke) {
this.graphics.lineStyle(headerStroke._lineThickness);
this.graphics.lineBitmapStyle(headerStroke._bitmap, headerStroke._matrix, headerStroke._repeat, headerStroke._smooth);
}

// header fill
if (headerRect is SolidColorRect) this.graphics.beginFill(headerRect._backgroundColor, headerRect._alpha);
if (headerRect is GradientColorRect) this.graphics.beginGradientFill(headerRect._gradientType, headerRect._colors, headerRect._alphas, headerRect._ratios, headerRect._matrix, headerRect._spreadMethod, headerRect._interpolationMethod, headerRect._focalPointRatio);
if (headerRect is BitmapRect) this.graphics.beginBitmapFill(headerRect._bitmap, headerRect._matrix, headerRect._repeat, headerRect._smooth);

this.graphics.drawRoundRectComplex(pos.x + headerPadding.left, pos.y + headerPadding.top, w - (headerPadding.left + headerPadding.right), headerHeight,
headerRect._radius[0], headerRect._radius[1], headerRect._radius[2], headerRect._radius[3]);
this.graphics.endFill();

// title
titleField.width = w - (headerPadding.left + headerPadding.right);
titleField.text = tt;
titleField.height = headerHeight;
titleField.x = pos.x + headerPadding.left + titlePadding.left;
titleField.y = pos.y + headerPadding.top + titlePadding.top;

// text
textField.width = w - (textPadding.right + textPadding.left);
textField.height = h - (textPadding.top + textPadding.bottom + headerPadding.top + headerPadding.bottom + headerHeight + buttonbarHeight + buttonbarPadding.top + buttonbarPadding.bottom);
textField.text = t;
textField.x = pos.x + textPadding.right;
textField.y = pos.y + textPadding.top + headerHeight + headerPadding.bottom + headerPadding.top;

// formats
textField.setTextFormat(textFormat);
titleField.setTextFormat(titleFormat);
textField.selectable = selectable;
titleField.selectable = selectable;
textField.multiline = true;
textField.wordWrap = true;

// buttons
var xCoord:Number;
if (buttons.length > 0) xCoord = pos.x + w - buttons[0].w - buttonbarPadding.right;
for (var i:int = 0; i < buttons.length; i++) {
if (i > 0) xCoord -= buttons[i].w + buttonInterval;
buttons[i].x = xCoord;
buttons[i].y = pos.y + h - buttons[i].h - buttonbarPadding.bottom;
}
}


}

}

And thats it for now! Now we can label and set size of each button separately, and they are positioned properly!

Thanks for reading!
Read more »

Sunday, February 1, 2015

Creating EasyTooltip class Part 20

In this tutorial well smoothen our tooltip movement even more.

First of all, well pass a new parameter to the TooltipCursor class when creating an instance of it in EasyTooltip.

Go to the constructor of the EasyTooltip class and pass smoothMovement value as the third parameter of the cursor:

/**
* Create a Tooltip manager. Needed for creating and managing tooltips.
* @paramparent Reference to the parent of tooltips - the container, which will contain the objects that will be rolled over.
* @paramparentWidth Width of the parent.
* @paramparentHeight Height of the parent.
* @paramsmoothMovement The movement smoothener - the bigger the value, the smoother the movement. 1 = no smoothment.
* @paramspawnDelay Delay in milliseconds of how long the user has to hold their mouse over the object to invoke a tooltip.
*/

public function EasyTooltip(parent:DisplayObjectContainer, parentWidth:int, parentHeight:int, smoothMovement:Number = 3, spawnDelay:int = 0)
{
smooth = smoothMovement;
delay = spawnDelay;
par = parent;
listeners = [];
parW = parentWidth;
parH = parentHeight;
cursor = new TooltipCursor(parentWidth, parentHeight, smoothMovement);
cursor.mouseChildren = false;
cursor.mouseEnabled = false;
parent.addChild(cursor);
cursor.addEventListener(Event.ENTER_FRAME, onFrame);
setStyle(new TooltipStyle());
trace("Tooltip manager created!");
}

Full EasyTooltip class:

package com.kircode.EasyTooltip 
{
import flash.display.DisplayObjectContainer;
import flash.display.DisplayObject;
import flash.events.Event;
/**
* Utility for creation of tooltips.
* @author Kirill Poletaev
*/
public class EasyTooltip
{

private var par:DisplayObject;
public var listeners:Array;
private var cursor:TooltipCursor;
private var parW:int;
private var parH:int;
private var delay:int;
private var smooth:Number;

/**
* Create a Tooltip manager. Needed for creating and managing tooltips.
* @paramparent Reference to the parent of tooltips - the container, which will contain the objects that will be rolled over.
* @paramparentWidth Width of the parent.
* @paramparentHeight Height of the parent.
* @paramsmoothMovement The movement smoothener - the bigger the value, the smoother the movement. 1 = no smoothment.
* @paramspawnDelay Delay in milliseconds of how long the user has to hold their mouse over the object to invoke a tooltip.
*/

public function EasyTooltip(parent:DisplayObjectContainer, parentWidth:int, parentHeight:int, smoothMovement:Number = 3, spawnDelay:int = 0)
{
smooth = smoothMovement;
delay = spawnDelay;
par = parent;
listeners = [];
parW = parentWidth;
parH = parentHeight;
cursor = new TooltipCursor(parentWidth, parentHeight, smoothMovement);
cursor.mouseChildren = false;
cursor.mouseEnabled = false;
parent.addChild(cursor);
cursor.addEventListener(Event.ENTER_FRAME, onFrame);
setStyle(new TooltipStyle());
trace("Tooltip manager created!");
}

/**
* Set a new style for the tooltips.
* @paramstyle TooltipStyle object that defines the style.
*/

public function setStyle(style:TooltipStyle):void {
cursor.setStyle(style);
}

/**
* Add a Tooltip listener.
* @paramlistener Object, which invokes the tooltip on roll over.
* @paramtooltip Message to be displayed.
* @returnNewly created Tooltip object. Can be used to dynamically change its properties in real-time.
*/

public function addListener(listener:DisplayObject, tooltip:String):Tooltip {
var tip:Tooltip = new Tooltip(tooltip);
var list:TooltipListener = new TooltipListener(listener, tip, delay);
listeners.push(list);
return tip;
}

private function onFrame(evt:Event):void {
cursor.x += (par.mouseX - cursor.x)/smooth;
cursor.y += (par.mouseY - cursor.y)/smooth;
var displayInd:int = -1;
for (var i:int = 0; i < listeners.length; i++) {
if (listeners[i].tip.display) {
displayInd = i;
break;
}
}
if (displayInd == -1) {
cursor.alpha = 0;
}else {
cursor.alpha = 1;
cursor.setText(listeners[displayInd].tip.msg);
}
}

}

}

Now go to TooltipCursor class. Declare 3 new variables - smooth, realX and realY:

private var smooth:Number;
private var realX:int = 0;
private var realY:int = 0;

Receive the third parameter the the constructor and apply its value to smooth:

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

Now go to updateDisplay() function. Here, update the values of realX and realY to simulate smooth movement. The destination are actual_x and actual_y values.

realX += (actual_x - realX) / smooth;
realY += (actual_y - realY) / smooth;

Now in the whole updateDisplay() function, replace actual_x and actual_y with realX and realY.

private function updateDisplay():void {
realX += (actual_x - realX) / smooth;
realY += (actual_y - realY) / smooth;

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(realX, realY, 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(realX, realY, 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(realX, realY, 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 = realX + style.textPadding.left;
txt.y = realY + style.textPadding.top;

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

And were done - you can now test the movie and see that there are no "jumpy" movements - everything moves smoothly and neatly.

Full TooltipCursor 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;
private var smooth:Number;
private var realX:int = 0;
private var realY:int = 0;

public function TooltipCursor(pW:int, pH:int, sm:Number)
{
smooth = sm;
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 {
realX += (actual_x - realX) / smooth;
realY += (actual_y - realY) / smooth;

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(realX, realY, 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(realX, realY, 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(realX, realY, 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 = realX + style.textPadding.left;
txt.y = realY + style.textPadding.top;

var i:int;
for (i = 0; i < content.length; i++) {
content[i].c.x = realX + content[i].x;
content[i].c.y = realY + 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 doesnt 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 doesnt 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;
}
}
}

}

}

}

Thanks for reading!

The results:

Read more »

Wednesday, January 28, 2015

The Flash AS3 Tween Class

In this tutorial, were going to learn how to use the Flash AS3 Tween Class. The tween class lets you create tween animation using code.

Step 1

Lets first create a movie clip that we will use with our ActionScript 3 tween.

Draw a small circle and convert it into a movie clip symbol. Dont forget to give this circle an instance name. Lets name it circle_mc.

Step 2

Create a new layer for the ActionScript. Select the first frame of this layer, and then open up the Actions panel.

Step 3

We first need to import the Flash AS3 Tween class so that we will be able to use it. On the first line, type:

import fl.transitions.Tween;

Aside from the tween class, we also need to import the easing classes. So in the next line, type:

import fl.transitions.easing.*;

The easing classes allow us to specify different kinds of tween effects. There are 6 easing classes in the AS3 easing package. These are:
  • Back
  • Bounce
  • Elastic
  • None
  • Regular
  • Strong

Each easing type will apply a different effect to your tween animation.

And now that weve imported the necessary classes, lets create a tween using code.

Step 4

To create an AS3 tween object, type new Tween() and assign in to a variable. Lets name this tween tweenX. After the import statements, type:

var tweenX:Tween = new Tween();

This creates a new tween object named tweenX. Lets use this tween object to make our circle on the stage move from the left to the right. To do that, well need to pass a few arguments to the Tween() constructor.

The Tween() constructor needs 7 arguments. First, we need to specify the object that we want to tween. In this case, that would be circle_mc. So type in circle_mc inside the parentheses of the Tween() constructor.

var tweenX:Tween = new Tween(circle_mc);

After that, we need to specify the name of the property of the object that we would like to tween. If you wanted to create a fading animation, then you can specify the alpha property. If you wanted to create a scaling animation then you can specify the width, height, scaleX or scaleY properties. But since we want to make the circle move horizontally, then we can use the x property. So lets pass that to the Tween() constructor as well:

var tweenX:Tween = new Tween(circle_mc, "x");

The property name is a string so it should be in quotation marks.

The third argument we need to pass is the easing type that we want to use. The easing type will apply an effect to the movement in the tween. Lets try using Bounce.easeOut for this tween. This will create a bouncing effect when the circle reaches the end of the animation.

var tweenX:Tween = new Tween(circle_mc, "x", Bounce.easeOut);

The fourth argument we need to pass is for the starting value of the objects property that we are tweening. So since we are using the x property, this next argument that we pass will be for the starting x position of the circle. Lets specify a value of 100.

var tweenX:Tween = new Tween(circle_mc, "x", Bounce.easeOut, 100);

So when the tween starts, circle_mc will have a starting x position of 100.

The fifth argument we need to pass is for the ending value of the objects property. Lets specify a value of 400.

var tweenX:Tween = new Tween(circle_mc, "x", Bounce.easeOut, 100, 400);

So this means that at the end of the tween, our circle will be positioned at x = 400.

The sixth argument we need to pass is for the duration of the tween. You can specify the duration in frames or in seconds. Lets specify a duration of 3 seconds.

var tweenX:Tween = new Tween(circle_mc, "x", Bounce.easeOut, 100, 400, 3);

The seventh and last argument we need to specify is a boolean - true or false. If we specify true, then this means that the duration will be in seconds. If we specify false, then the duration will be in frames. Since we want our tween to play over a period of 3 seconds, then we should specify a value of true.

var tweenX:Tween = new Tween(circle_mc, "x", Bounce.easeOut, 100, 400, 3, true);

And now our tween is complete. Test the movie to preview the animation.

Step 5

Here is a list of all the other easing functions that you can use. Try them out to see how they look like. Simply replace the third argument in the Tween() constructor with a new easing function of your choice.

Back Bounce Elastic
Back.easeIn
Back.easeOut
Back.easeInOut
Bounce.easeIn
Bounce.easeOut
Bounce.easeInOut
Elastic.easeIn
Elastic.easeOut
Elastic.easeInOut
None Regular Strong
None.easeNone Regular.easeIn
Regular.easeOut
Regular.easeInOut
Strong.easeIn
Strong.easeOut
Strong.easeInOut

Step 6

If you want to tween other movie clips, then youll have to create new tween objects for each movie clip that you want to tween. Even if you want to tween different properties of the same movie clip instance, youll still need new tween objects for each. So if we also wanted to tween the scaleX and scaleY properties of circle_mc, then well need to create two more tween objects for each property.

import fl.transitions.Tween;
import fl.transitions.easing.*;

var tweenX:Tween = new Tween(circle_mc, "x", Bounce.easeOut, 100, 400, 3, true);
var tweenScaleX:Tween = new Tween(circle_mc, "scaleX", Bounce.easeOut, 1, 2, 3, true);
var tweenScaleY:Tween = new Tween(circle_mc, "scaleY", Bounce.easeOut, 1, 2, 3, true);

Here, aside from moving horizontally, the circle will also grow. Were starting out with a scaleX and scaleY of 1, and moving up to a value of 2 within 3 seconds. This means that the circle will grow from 100% to 200% both horizontally and vertically within that period.

We dont need to use the same easing functions, starting values, ending values, and durations for all our tweens. Try playing around with different values, and see what you can come up with.

And that concludes this Flash AS3 Tween Class tutorial.
Read more »

Tuesday, January 27, 2015

Creating Advanced Alert Window class Part 19

Today we will work on the ability to create custom skins for buttons with ease.

Start by creating a new class meant specifically for skinning buttons. Call it AdvAlertButtonSkin.as.

Inside, declare and set values to all the skinning variables from AdvAlertButton, plus a new variable called filters (which is an array and which is enmpty by default):

package com.kircode.AdvAlert 
{
import flash.filters.DropShadowFilter;
import flash.text.TextFormat;
import flash.geom.Point;
/**
* Object containing skinning data for AdvAlertButton.
* @author Kirill Poletaev
*/
public class AdvAlertButtonSkin
{

public var w:Number;
public var h:Number;
public var textFormat:TextFormat;
public var bgStroke:*;
public var bgRect:*;
public var pos:Point;
public var textPadding:TextPadding;
public var filters:Array;

public function AdvAlertButtonSkin()
{
// default values
w = 80;
h = 30;
textFormat = new TextFormat("Arial", 16, 0xffffff);
textFormat.align = "center";
bgStroke = new SolidColorStroke(2, 0x333399, 1);
bgRect = new SolidColorRect(0x6666ff, [3, 3, 3, 3], 1);
pos = new Point(0, 0);
textPadding = new TextPadding(3, 0, 3, 0);
filters = [];
}

}

}

Go to AdvAlertButton.as, declare a new variable called filt (which will hold the filters values):

private var filt:Array;

Update the constructor so that it can receive an optional skin parameter, set it to a new AdvAlertButtonSkin object by default. Pass the skin value to setSkin():

public function AdvAlertButton(label:String, skin:AdvAlertButtonSkin = null) 
{
if (skin == null) skin = new AdvAlertButtonSkin();
txt = label;
textField = new TextField();
addChild(textField);

setSkin(skin);

updateDraw();
}

In setSkin() we receive all the values from the skin and apply them to local variables:

public function setSkin(skin:AdvAlertButtonSkin):void {
w = skin.w;
h = skin.h;
textFormat = skin.textFormat;
bgStroke = skin.bgStroke;
bgRect = skin.bgRect;
pos = skin.pos;
textPadding = skin.textPadding;
filt = skin.filters;
}

Add a line to updateDraw() which updates filters:

//filters
this.filters = filt;

Full AdvAlertButton.as code so far:

package com.kircode.AdvAlert 
{
import flash.display.MovieClip;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;

/**
* Advanced Alert window object.
* @author Kirill Poletaev
*/
public class AdvAlertButton extends MovieClip
{

public var w:Number;
public var h:Number;
private var textFormat:TextFormat;
private var bgStroke:*;
private var bgRect:*;
private var pos:Point;
private var textPadding:TextPadding;
private var filt:Array;

private var textField:TextField;
private var txt;

/**
* Button object placed in the alert window.
* @paramlabel Text label of the button.
*/

public function AdvAlertButton(label:String, skin:AdvAlertButtonSkin = null)
{
if (skin == null) skin = new AdvAlertButtonSkin();
txt = label;
textField = new TextField();
addChild(textField);

setSkin(skin);

updateDraw();
}

public function setSkin(skin:AdvAlertButtonSkin):void {
w = skin.w;
h = skin.h;
textFormat = skin.textFormat;
bgStroke = skin.bgStroke;
bgRect = skin.bgRect;
pos = skin.pos;
textPadding = skin.textPadding;
filt = skin.filters;
}

public function updateDraw():void {
this.graphics.clear();

//filters
this.filters = filt;

// bg stroke
if (bgStroke is SolidColorStroke) {
this.graphics.lineStyle(bgStroke._lineThickness, bgStroke._lineColor, bgStroke._lineAlpha);
}
if (bgStroke is GradientColorStroke) {
this.graphics.lineStyle(bgStroke._lineThickness);
this.graphics.lineGradientStyle(bgStroke._gradientType, bgStroke._colors, bgStroke._alphas, bgStroke._ratios, bgStroke._matrix, bgStroke._spreadMethod, bgStroke._interpolationMethod, bgStroke._focalPointRatio);
}
if (bgStroke is BitmapStroke) {
this.graphics.lineStyle(bgStroke._lineThickness);
this.graphics.lineBitmapStyle(bgStroke._bitmap, bgStroke._matrix, bgStroke._repeat, bgStroke._smooth);
}

// bg fill
if (bgRect is SolidColorRect) this.graphics.beginFill(bgRect._backgroundColor, bgRect._alpha);
if (bgRect is GradientColorRect) this.graphics.beginGradientFill(bgRect._gradientType, bgRect._colors, bgRect._alphas, bgRect._ratios, bgRect._matrix, bgRect._spreadMethod, bgRect._interpolationMethod, bgRect._focalPointRatio);
if (bgRect is BitmapRect) this.graphics.beginBitmapFill(bgRect._bitmap, bgRect._matrix, bgRect._repeat, bgRect._smooth);

this.graphics.drawRoundRectComplex(pos.x, pos.y, w, h,
bgRect._radius[0], bgRect._radius[1], bgRect._radius[2], bgRect._radius[3]);
this.graphics.endFill();

// text field
textField.width = w;
textField.height = h;
textField.text = txt;
textField.setTextFormat(textFormat);
textField.selectable = false;
textField.x = pos.x + textPadding.right;
textField.y = pos.y + textPadding.top;
}


}

}

You can now go to main.as and create custom skins for buttons. Example:

var cancelSkin = new AdvAlertButtonSkin();
cancelSkin.bgRect = new SolidColorRect(0xff4444, [3, 3, 3, 3]);
cancelSkin.bgStroke = new SolidColorStroke(2, 0x993333);
cancelSkin.filters = [new GlowFilter(0xff0000,1,6,6,2,3)];

AlertManager = new AdvAlertManager(this, stage.stageWidth, stage.stageHeight);
AlertManager.alert("This is an alert window with the default skin.", "Example alert!", [new AdvAlertButton("OK"), new AdvAlertButton("Cancel", cancelSkin), new AdvAlertButton("Back")]);

The results:



Thank for reading!
Read more »

Wednesday, January 21, 2015

Creating EasyTooltip class Part 8

In this tutorial we will improve the auto-sizing algorithm by calculating the best direction in which the tooltip will be displayed, relative to the mouse.

Go to TooltipCursor class and declare a new variable "direction":

private var direction:String = "";

In the updateSize() function we shall calcualte which direction the tooltip should be casted, relative to the mouse of the user. This is done in order to display as much content as possible, therefore - the tooltip is casted in the direction, which has more free space for it.

Right now we are going to add only 2 directions - topright and topleft. The algorithm behind it is actually fairly simple - all we do is check in which half of the parent (stage in this case) the mouse is located. If mouse is in the left half of the parent, then there is more space on the right - so the direction will be "topright", and vice versa.

Other than just setting the direction values, we will also set actual_x and actual_y values. For topright, we keep them as they were before, but for topleft - move them to the left by X pixels, where X is the width of the tooltip.

// calculate best direction
if (this.x <= parentW * 0.5) {
direction = "topright";
actual_x = 0 + style.offsetX;
actual_y = -h + style.offsetY;
} else
if (this.x > parentW * 0.5) {
direction = "topleft";
actual_x = -w + style.offsetX;
actual_y = -h + style.offsetY;
}

The code we had after this remains the same, except that we execute it only if direction is topright. Also, instead of adding 4 pixels in the while loop - add just 1 (for more precision):

// If sticks out on the left:
if(direction == "topright"){
// 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;
} else {
// if doesnt 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 += 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 = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true;
}
}
}

If direction is topleft, the code is similar, yet some values need to be changed.

Take a look:

// If sticks out on the right:
if(direction == "topleft"){
if (this.x + actual_x <= 0) {
txt.wordWrap = true;
actual_x = -this.x;
w = this.x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
} else {
// if doesnt 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) {
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 = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true;
}
}
}

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

/**
* 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();
background.graphics.beginFill(style.backgroundColor, style.backgroundAlpha);
background.graphics.drawRect(actual_x, actual_y, w, h);
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 {
w = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;

// calculate best direction
if (this.x <= parentW * 0.5) {
direction = "topright";
actual_x = 0 + style.offsetX;
actual_y = -h + style.offsetY;
} else
if (this.x > parentW * 0.5) {
direction = "topleft";
actual_x = -w + style.offsetX;
actual_y = -h + style.offsetY;
}

// If sticks out on the left:
if(direction == "topright"){
// 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;
} else {
// if doesnt 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 += 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 = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true;
}
}
}

// If sticks out on the right:
if(direction == "topleft"){
if (this.x + actual_x <= 0) {
txt.wordWrap = true;
actual_x = -this.x;
w = this.x;
h = txt.textHeight + 4 + style.textPadding.top + style.textPadding.bottom;
} else {
// if doesnt 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) {
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 = txt.textWidth + 4 + style.textPadding.left + style.textPadding.right;
break;
}
txt.wordWrap = true;
}
}
}

}

}

}

Thanks for reading!

Here are the results so far:

Read more »