Showing posts with label class. Show all posts
Showing posts with label class. Show all posts
Friday, February 6, 2015
Creating EasyTooltip class Part 15
In this tutorial well add support for gradient strokes and background fills.
Create 2 new classes - GradientColorStroke and GradientColorRect. As I already said in earlier tutorials, the whole skinning system is very similar to the one in AdvAlert library.
GradientColorStroke.as code:
And GradientColorRect.as code:
Go to TooltipCursor.as. In the updateDisplay() function, add 2 new if..statements, that execute the code if backgroundStroke is a GradientColorStroke object and if backgroundRect is a GradientColorRect object.
Use the provided values to draw gradient stroke and box. Inside of each of these if...statements, add one more conditional, which checks if the _matrix object of that object is not null. If so, set the tx and ty variables of that matrix to actual_x and actual_y. This will ensure that the gradient box looks similar no matter in which direction it is stretched.
Full TooltipCursor.as code:
And were done!
Thanks for reading!
Heres an example of usage of the 2 new classes:
Read more »
Create 2 new classes - GradientColorStroke and GradientColorRect. As I already said in earlier tutorials, the whole skinning system is very similar to the one in AdvAlert library.
GradientColorStroke.as code:
package com.kircode.EasyTooltip
{
import flash.geom.Matrix;
/**
* ...
* @author Kirill Poletaev
*/
public class GradientColorStroke
{
public var _lineThickness:Number;
public var _gradientType:String;
public var _colors:Array;
public var _alphas:Array;
public var _ratios:Array;
public var _matrix:Matrix;
public var _spreadMethod:String;
public var _interpolationMethod:String;
public var _focalPointRatio:Number;
/**
* Create a gradient colored line stroke. Uses same parameters as lineGradientStyle() + lineThickness.
* @paramlineThickness Thickness of the line stroke.
* @paramgradientType A value from the GradientType class that specifies which gradient type to use: GradientType.LINEAR or GradientType.RADIAL.
* @paramcolors An array of RGB hexadecimal color values used in the gradient; for example, red is 0xFF0000, blue is 0x0000FF, and so on. You can specify up to 15 colors. For each color, specify a corresponding value in the alphas and ratios parameters.
* @paramalphas An array of alpha values for the corresponding colors in the colors array; valid values are 0 to 1. If the value is less than 0, the default is 0. If the value is greater than 1, the default is 1.
* @paramratios An array of color distribution ratios; valid values are 0-255. This value defines the percentage of the width where the color is sampled at 100%. The value 0 represents the left position in the gradient box, and 255 represents the right position in the gradient box.
* @parammatrix A transformation matrix as defined by the flash.geom.Matrix class. The flash.geom.Matrix class includes a createGradientBox() method, which lets you conveniently set up the matrix for use with the beginGradientFill() method.
* @paramspreadMethod A value from the SpreadMethod class that specifies which spread method to use, either: SpreadMethod.PAD, SpreadMethod.REFLECT, or SpreadMethod.REPEAT.
* @paraminterpolationMethod A value from the InterpolationMethod class that specifies which value to use: InterpolationMethod.LINEAR_RGB or InterpolationMethod.RGB
* @paramfocalPointRation A number that controls the location of the focal point of the gradient. 0 means that the focal point is in the center. 1 means that the focal point is at one border of the gradient circle. -1 means that the focal point is at the other border of the gradient circle. A value less than -1 or greater than 1 is rounded to -1 or 1.
*/
public function GradientColorStroke(lineThickness:Number, gradientType:String, colors:Array, alphas:Array, ratios:Array, matrix:Matrix = null, spreadMethod:String = "pad", interpolationMethod:String = "rgb", focalPointRation:Number = 0)
{
_lineThickness = lineThickness;
_gradientType = gradientType;
_colors = colors;
_alphas = alphas;
_ratios = ratios;
_matrix = matrix;
_spreadMethod = spreadMethod;
_interpolationMethod = interpolationMethod;
_focalPointRatio = focalPointRation;
}
}
}
And GradientColorRect.as code:
package com.kircode.EasyTooltip
{
import flash.geom.Matrix;
/**
* ...
* @author Kirill Poletaev
*/
public class GradientColorRect
{
public var _gradientType:String;
public var _colors:Array;
public var _alphas:Array;
public var _ratios:Array;
public var _matrix:Matrix;
public var _spreadMethod:String;
public var _interpolationMethod:String;
public var _focalPointRatio:Number;
public var _radius:Array;
/**
* Create a gradient filled rectangle. Has the same parameters as beginGradientFill(), plus cornerRadius.
* @paramgradientType A value from the GradientType class that specifies which gradient type to use: GradientType.LINEAR or GradientType.RADIAL.
* @paramcolors An array of RGB hexadecimal color values used in the gradient; for example, red is 0xFF0000, blue is 0x0000FF, and so on. You can specify up to 15 colors. For each color, specify a corresponding value in the alphas and ratios parameters.
* @paramalphas An array of alpha values for the corresponding colors in the colors array; valid values are 0 to 1. If the value is less than 0, the default is 0. If the value is greater than 1, the default is 1.
* @paramratios An array of color distribution ratios; valid values are 0-255. This value defines the percentage of the width where the color is sampled at 100%. The value 0 represents the left position in the gradient box, and 255 represents the right position in the gradient box.
* @parammatrix A transformation matrix as defined by the flash.geom.Matrix class. The flash.geom.Matrix class includes a createGradientBox() method, which lets you conveniently set up the matrix for use with the beginGradientFill() method.
* @paramspreadMethod A value from the SpreadMethod class that specifies which spread method to use, either: SpreadMethod.PAD, SpreadMethod.REFLECT, or SpreadMethod.REPEAT.
* @paraminterpolationMethod A value from the InterpolationMethod class that specifies which value to use: InterpolationMethod.LINEAR_RGB or InterpolationMethod.RGB
* @paramfocalPointRation A number that controls the location of the focal point of the gradient. 0 means that the focal point is in the center. 1 means that the focal point is at one border of the gradient circle. -1 means that the focal point is at the other border of the gradient circle. A value less than -1 or greater than 1 is rounded to -1 or 1.
* @paramcornerRadius Radius of the corners of the box - top left, top right, bottom left, bottom right.
*/
public function GradientColorRect(gradientType:String, colors:Array, alphas:Array, ratios:Array, matrix:Matrix = null, spreadMethod:String = "pad", interpolationMethod:String = "rgb", focalPointRation:Number = 0, cornerRadius:Array = null)
{
if (cornerRadius == null) cornerRadius = [10, 10, 0, 0];
_gradientType = gradientType;
_colors = colors;
_alphas = alphas;
_ratios = ratios;
_matrix = matrix;
_spreadMethod = spreadMethod;
_interpolationMethod = interpolationMethod;
_focalPointRatio = focalPointRation;
_radius = cornerRadius;
}
}
}
Go to TooltipCursor.as. In the updateDisplay() function, add 2 new if..statements, that execute the code if backgroundStroke is a GradientColorStroke object and if backgroundRect is a GradientColorRect object.
Use the provided values to draw gradient stroke and box. Inside of each of these if...statements, add one more conditional, which checks if the _matrix object of that object is not null. If so, set the tx and ty variables of that matrix to actual_x and actual_y. This will ensure that the gradient box looks similar no matter in which direction it is stretched.
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.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();
}
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;
}
Full TooltipCursor.as 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.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();
}
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 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;
}
}
}
}
}
}
And were done!
Thanks for reading!
Heres an example of usage of the 2 new classes:
var myStyle:TooltipStyle = new TooltipStyle();
myStyle.minWidth = 240;
myStyle.maxWidth = 0;
myStyle.offsetX = -10;
myStyle.offsetY = -10;
var matrix1:Matrix = new Matrix();
matrix1.createGradientBox(240, 200, 1.57);
myStyle.backgroundRect = new GradientColorRect(GradientType.LINEAR, [0, 0], [0.2, 1], [0, 255], matrix1, "pad", "rgb", 0, [0, 0, 0, 0]);
var matrix2:Matrix = new Matrix();
matrix2.createGradientBox(240, 200, 1.57);
myStyle.backgroundStroke = new GradientColorStroke(2, GradientType.LINEAR, [0x000000, 0xffffff], [1, 1], [0, 255], matrix2, "pad", "rgb", 0);
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");
Thursday, February 5, 2015
Creating EasyKeyboard class Part 3
Today we will add the ability to add listeners to keyboard by specifying key names instead of keycodes.
This way, well be able to set a key listener to the "A" key, for example, by simply passing "A" as one of the values to one of the methods of EasyKeyboard, instead of sending the key code of the key.
To know which name corresponds to which key, well need to add an array keyLabels in EasyKeyboard.as which contains names for all the keys. The index of each element in this array corresponds to the keys key code:
Now create a new function called addEasyListener. The parameters are the same as in addListener, except for the first one.
Instead of receiving keyCode, we receive a string keyName value. Then, in the function, we check which key code belongs to the specified key by looping through the array. If no match is found, then throw an error. If everything went smoothly, then simply call addListener() method with all the same parameter values as we received, and keyCode set to what weve calculated:
Full EasyKeyboard.as code:
If you go to main.as now, you can call the addEasyListener to add keyboard listeners this way:
Thats all for today.
Thanks for reading!
Read more »
This way, well be able to set a key listener to the "A" key, for example, by simply passing "A" as one of the values to one of the methods of EasyKeyboard, instead of sending the key code of the key.
To know which name corresponds to which key, well need to add an array keyLabels in EasyKeyboard.as which contains names for all the keys. The index of each element in this array corresponds to the keys key code:
private var keyLabels:Array = ["0","1","2","3","4","5","6","7","Backspace","Tab","10","11","Center","Enter","14","15","Shift","Control","Alt","Pause","Caps Lock","21","22","23","24","25","26","27","28","29","30","31","Space","Page Up","Page Down","End","Home","Left","Up","Right","Down","41","42","43","44","Insert","Delete","47","0","1","2","3","4","5","6","7","8","9","58","59","60","61","62","63","64","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Windows","Windows","Menu","94","95","Num 0","Num 1","Num 2","Num 3","Num 4","Num 5","Num 6","Num 7","Num 8","Num 9","Num *","Num +","108","Num -","Num .","Num /","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","Num Lock","Scroll Lock","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185",";","+",",","-",".","/","~","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","[","\","]","","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254","255"];
Now create a new function called addEasyListener. The parameters are the same as in addListener, except for the first one.
Instead of receiving keyCode, we receive a string keyName value. Then, in the function, we check which key code belongs to the specified key by looping through the array. If no match is found, then throw an error. If everything went smoothly, then simply call addListener() method with all the same parameter values as we received, and keyCode set to what weve calculated:
/**
* Add event listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
*/
public function addEasyListener(keyName:String, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addListener(code, handlerDown, handlerUp, alt, ctrl, shift);
}
Full EasyKeyboard.as code:
package com.kircode.EasyKeyboard
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
/**
* Utility for easy keyboard listener management.
* @author Kirill Poletaev
*/
public class EasyKeyboard
{
public var listeners:Array = [];
private var keyLabels:Array = ["0","1","2","3","4","5","6","7","Backspace","Tab","10","11","Center","Enter","14","15","Shift","Control","Alt","Pause","Caps Lock","21","22","23","24","25","26","27","28","29","30","31","Space","Page Up","Page Down","End","Home","Left","Up","Right","Down","41","42","43","44","Insert","Delete","47","0","1","2","3","4","5","6","7","8","9","58","59","60","61","62","63","64","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Windows","Windows","Menu","94","95","Num 0","Num 1","Num 2","Num 3","Num 4","Num 5","Num 6","Num 7","Num 8","Num 9","Num *","Num +","108","Num -","Num .","Num /","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","Num Lock","Scroll Lock","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185",";","+",",","-",".","/","~","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","[","\","]","","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254","255"];
private var st:Stage;
public function EasyKeyboard(stage:Stage)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, kDown);
stage.addEventListener(KeyboardEvent.KEY_UP, kUp);
stage.addEventListener(Event.ENTER_FRAME, frame);
st = stage;
}
private function frame(evt:Event):void {
}
/**
* Add event listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
*/
public function addListener(keyCode:int, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false):void {
listeners.push(new KeyListener(keyCode, handlerDown, handlerUp, alt, ctrl, shift));
}
/**
* Add event listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
*/
public function addEasyListener(keyName:String, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addListener(code, handlerDown, handlerUp, alt, ctrl, shift);
}
private function kDown(evt:KeyboardEvent):void {
for (var i:int = 0; i < listeners.length; i++) {
if (evt.keyCode == listeners[i].keyCode && listeners[i] is KeyListener && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerD) listeners[i].handlerD.call();
}
}
}
private function kUp(evt:KeyboardEvent):void {
for (var i:int = 0; i < listeners.length; i++) {
if (evt.keyCode == listeners[i].keyCode && listeners[i] is KeyListener && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerU) listeners[i].handlerU.call();
}
}
}
}
}
If you go to main.as now, you can call the addEasyListener to add keyboard listeners this way:
keyboard = new EasyKeyboard(stage);
keyboard.addEasyListener("A", function() { trace("Down"); }, function() { trace("Up"); } );
// LINE ABOVE EQUALS TO: keyboard.addListener(65, function() { trace("Down"); }, function() { trace("Up"); });
Thats all for today.
Thanks for reading!
Sunday, February 1, 2015
Creating Advanced Alert Window class Part 10
In this tutorial we will improve our skinning system. Well add support for skinning strokes and fills separately, so that its also possible to use solid colored, gradient and bitmap line strokes.
We will start by creating a new class called SolidColorStroke.as.
Add 3 variables:
Receive the values in constructor and apply them to these variables:
Now we need to go to SolidColorRect, GradientColorRect and BitmapRect and remove these three variables from each class completely.
New SolidColorRect.as:
New GradientColorRect.as:
New BitmapRect.as:
Go to AdvAlertSkin.as. Add 2 new variables - bgStroke and headerStroke, set them to new SolidColorStroke objects in the constructor:
Now go to AdvAlertWindow.as and add The headerStroke and bgStroke variables here too:
Apply values in the setSkin() function:
Now set line styles in updateDraw() before drawing the rectangles.
Full AdvAlertWindow.as code:
You can create an alert with a default skin in main.as:
And youll see that the default strokes are displayed properly. You are also able to set your own custom values for the stroke. The visuals of the alert window did not change, but the code behind it sure did - it is now easier to manage strokes and fills separately, and well add new types of stroke skinning in the next tutorials.
Thanks for reading!
Read more »
We will start by creating a new class called SolidColorStroke.as.
Add 3 variables:
public var _lineThickness:Number;
public var _lineColor:uint;
public var _lineAlpha:Number;
Receive the values in constructor and apply them to these variables:
package com.kircode.AdvAlert
{
/**
* ...
* @author Kirill Poletaev
*/
public class SolidColorStroke
{
public var _lineThickness:Number;
public var _lineColor:uint;
public var _lineAlpha:Number;
/**
* Create a solid colored line stroke for rectangles.
* @paramlineThickness Thickness of the stroke.
* @paramlineColor Color of the stroke.
* @paramlineAlpha Alpha channel of the stroke.
*/
public function SolidColorStroke(lineThickness:Number = 1, lineColor:uint = 0x333333, lineAlpha:Number = 1)
{
_lineThickness = lineThickness;
_lineColor = lineColor;
_lineAlpha = lineAlpha;
}
}
}
Now we need to go to SolidColorRect, GradientColorRect and BitmapRect and remove these three variables from each class completely.
New SolidColorRect.as:
package com.kircode.AdvAlert
{
/**
* ...
* @author Kirill Poletaev
*/
public class SolidColorRect
{
public var _backgroundColor:uint;
public var _radius:Array;
public var _alpha:Number;
/**
* Create a rectangle filled with solid color.
* @parambackgroundColor Background color fill of the box.
* @paramcornerRadius Radius of the corners of the box - top left, top right, bottom left, bottom right.
* @paramalpha Alpha channel of the background fill.
*/
public function SolidColorRect(backgroundColor:uint = 0xE2E2E2, cornerRadius:Array = null, alpha:Number = 1)
{
if (cornerRadius == null) cornerRadius = [10, 10, 0, 0];
_backgroundColor = backgroundColor;
_radius = cornerRadius;
_alpha = alpha
}
}
}
New GradientColorRect.as:
package com.kircode.AdvAlert
{
import flash.geom.Matrix;
/**
* ...
* @author Kirill Poletaev
*/
public class GradientColorRect
{
public var _gradientType:String;
public var _colors:Array;
public var _alphas:Array;
public var _ratios:Array;
public var _matrix:Matrix;
public var _spreadMethod:String;
public var _interpolationMethod:String;
public var _focalPointRatio:Number;
public var _radius:Array;
/**
* Create a gradient filled rectangle. Has the same parameters as beginGradientFill(), plus cornerRadius.
* @paramgradientType A value from the GradientType class that specifies which gradient type to use: GradientType.LINEAR or GradientType.RADIAL.
* @paramcolors An array of RGB hexadecimal color values used in the gradient; for example, red is 0xFF0000, blue is 0x0000FF, and so on. You can specify up to 15 colors. For each color, specify a corresponding value in the alphas and ratios parameters.
* @paramalphas An array of alpha values for the corresponding colors in the colors array; valid values are 0 to 1. If the value is less than 0, the default is 0. If the value is greater than 1, the default is 1.
* @paramratios An array of color distribution ratios; valid values are 0-255. This value defines the percentage of the width where the color is sampled at 100%. The value 0 represents the left position in the gradient box, and 255 represents the right position in the gradient box.
* @parammatrix A transformation matrix as defined by the flash.geom.Matrix class. The flash.geom.Matrix class includes a createGradientBox() method, which lets you conveniently set up the matrix for use with the beginGradientFill() method.
* @paramspreadMethod A value from the SpreadMethod class that specifies which spread method to use, either: SpreadMethod.PAD, SpreadMethod.REFLECT, or SpreadMethod.REPEAT.
* @paraminterpolationMethod A value from the InterpolationMethod class that specifies which value to use: InterpolationMethod.LINEAR_RGB or InterpolationMethod.RGB
* @paramfocalPointRation A number that controls the location of the focal point of the gradient. 0 means that the focal point is in the center. 1 means that the focal point is at one border of the gradient circle. -1 means that the focal point is at the other border of the gradient circle. A value less than -1 or greater than 1 is rounded to -1 or 1.
* @paramcornerRadius Radius of the corners of the box - top left, top right, bottom left, bottom right.
*/
public function GradientColorRect(gradientType:String, colors:Array, alphas:Array, ratios:Array, matrix:Matrix = null, spreadMethod:String = "pad", interpolationMethod:String = "rgb", focalPointRation:Number = 0, cornerRadius:Array = null)
{
if (cornerRadius == null) cornerRadius = [10, 10, 0, 0];
_gradientType = gradientType;
_colors = colors;
_alphas = alphas;
_ratios = ratios;
_matrix = matrix;
_spreadMethod = spreadMethod;
_interpolationMethod = interpolationMethod;
_focalPointRatio = focalPointRation;
_radius = cornerRadius;
}
}
}
New BitmapRect.as:
package com.kircode.AdvAlert
{
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;
public var _alpha:Number;
/**
* 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.
* @paramalpha Alpha channel of the background fill.
*/
public function BitmapRect(bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false, cornerRadius:Array = null, alpha:Number = 1)
{
if (cornerRadius == null) cornerRadius = [10, 10, 0, 0];
_bitmap = bitmap;
_matrix = matrix;
_repeat = repeat;
_smooth = smooth;
_radius = cornerRadius;
_alpha = alpha
}
}
}
Go to AdvAlertSkin.as. Add 2 new variables - bgStroke and headerStroke, set them to new SolidColorStroke objects in the constructor:
package com.kircode.AdvAlert
{
import flash.text.TextFormat;
/**
* Object containing skinning data for AdvAlertWindow.
* @author Kirill Poletaev
*/
public class AdvAlertSkin
{
public var textPadding:TextPadding;
public var headerPadding:TextPadding;
public var titlePadding:TextPadding;
public var headerHeight:int;
public var titleFormat:TextFormat;
public var textFormat:TextFormat;
public var selectable:Boolean;
public var headerRect:*;
public var bgRect:*;
public var bgStroke:*;
public var headerStroke:*;
public function AdvAlertSkin()
{
// default values
textPadding = new TextPadding(5, 5, 5, 5);
headerPadding = new TextPadding(5, 5, 5, 5);
titlePadding = new TextPadding(2, 2, 2, 2);
headerHeight = 30;
titleFormat = new TextFormat();
titleFormat.size = 20;
titleFormat.font = "Arial";
titleFormat.bold = true;
titleFormat.color = 0xffffff;
textFormat = new TextFormat();
textFormat.size = 16;
textFormat.font = "Arial";
textFormat.color = 0xffffff;
selectable = false;
bgRect = new SolidColorRect(0x7777cc, [10, 10, 10, 10], 1);
headerRect = new SolidColorRect(0x9999ff, [10, 10, 0, 0], 1);
bgStroke = new SolidColorStroke(2, 0x4444aa, 1);
headerStroke = new SolidColorStroke(0, 0x000000, 0);
}
}
}
Now go to AdvAlertWindow.as and add The headerStroke and bgStroke variables here too:
private var headerStroke:*;
private var bgStroke:*;
Apply values in the setSkin() function:
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;
}
Now set line styles in updateDraw() before drawing the rectangles.
// bg stroke
if (bgStroke is SolidColorStroke) {
this.graphics.lineStyle(bgStroke._lineThickness, bgStroke._lineColor, bgStroke._lineAlpha);
}
// header stroke
if (headerStroke is SolidColorStroke) {
this.graphics.lineStyle(headerStroke._lineThickness, headerStroke._lineColor, headerStroke._lineAlpha);
}
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 textField:TextField;
private var titleField:TextField;
private var textPadding:TextPadding;
private var headerPadding:TextPadding;
private var titlePadding:TextPadding;
private var headerHeight:int;
private var titleFormat:TextFormat;
private var textFormat:TextFormat;
private var selectable:Boolean;
private var headerRect:*;
private var bgRect:*;
private var headerStroke:*;
private var bgStroke:*;
public function AdvAlertWindow(pt:String, ptt:String, pw:int, ph:int, ppos:Point, sk:AdvAlertSkin)
{
t = pt;
tt = ptt;
w = pw;
h = ph;
pos = ppos;
setSkin(sk);
textField = new TextField();
addChild(textField);
titleField = new TextField();
addChild(titleField);
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;
}
public function updateDraw():void {
this.graphics.clear();
// bg stroke
if (bgStroke is SolidColorStroke) {
this.graphics.lineStyle(bgStroke._lineThickness, bgStroke._lineColor, bgStroke._lineAlpha);
}
// bg fill
if (bgRect is SolidColorRect) {
this.graphics.beginFill(bgRect._backgroundColor, bgRect._alpha);
this.graphics.drawRoundRectComplex(pos.x, pos.y, w, h,
bgRect._radius[0], bgRect._radius[1], bgRect._radius[2], bgRect._radius[3]);
this.graphics.endFill();
}
if (bgRect is GradientColorRect) {
this.graphics.beginGradientFill(bgRect._gradientType, bgRect._colors, bgRect._alphas, bgRect._ratios, bgRect._matrix, bgRect._spreadMethod, bgRect._interpolationMethod, bgRect._focalPointRatio);
this.graphics.drawRoundRectComplex(pos.x, pos.y, w, h,
bgRect._radius[0], bgRect._radius[1], bgRect._radius[2], bgRect._radius[3]);
this.graphics.endFill();
}
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);
}
// header fill
if (headerRect is SolidColorRect) {
this.graphics.beginFill(headerRect._backgroundColor, headerRect._alpha);
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();
}
if (headerRect is GradientColorRect) {
this.graphics.beginGradientFill(headerRect._gradientType, headerRect._colors, headerRect._alphas, headerRect._ratios, headerRect._matrix, headerRect._spreadMethod, headerRect._interpolationMethod, headerRect._focalPointRatio);
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();
}
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);
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;
}
}
}
You can create an alert with a default skin in main.as:
package
{
import com.kircode.AdvAlert.AdvAlertManager;
import com.kircode.AdvAlert.AdvAlertSkin;
import com.kircode.AdvAlert.BitmapRect;
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* @author Kirill Poletaev
*/
public class main extends MovieClip
{
private var AlertManager:AdvAlertManager;
public function main()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(evt:Event):void {
AlertManager = new AdvAlertManager(this, stage.stageWidth, stage.stageHeight);
AlertManager.alert("Text message.", "Title");
}
}
}
And youll see that the default strokes are displayed properly. You are also able to set your own custom values for the stroke. The visuals of the alert window did not change, but the code behind it sure did - it is now easier to manage strokes and fills separately, and well add new types of stroke skinning in the next tutorials.
Thanks for reading!
Monday, January 26, 2015
Creating EasyKeyboard class Part 13
Today well further improve the abilities to remove listeners.
The removeListener() function works fine now, but theres a slight problem with removing TimedListeners. The issue is in the Timer, which doesnt stop working even after the listener was "removed". Aside from just removing it from the listeners array, we also need to reset and nullify the timer inside the listener.
You can witness the bug yourself if you create a timed listener and a key listener which removes the timed listener, then try to hold the key which triggers the timed event. If you remove the listener during the delay, youll see that the code dispatches the timed event one more time before stopping.
Lets fix this. Update the removeListener() function:
Now well add a function which removes all the listeners at once. Right now we have one called kill(), but it didnt actually remove all the listeners from the array - it just stops listening to the keyboard as a whole.
The removeAllListeners() method will loop through all listeners and remove them one by one, also taking care of timers the same way like in removeListener:
We should also call this function in kill():
So, to remove all the listeners, the user simply writes:
Full EasyKeyboard.as class code so far:
Thanks for reading!
Read more »
The removeListener() function works fine now, but theres a slight problem with removing TimedListeners. The issue is in the Timer, which doesnt stop working even after the listener was "removed". Aside from just removing it from the listeners array, we also need to reset and nullify the timer inside the listener.
You can witness the bug yourself if you create a timed listener and a key listener which removes the timed listener, then try to hold the key which triggers the timed event. If you remove the listener during the delay, youll see that the code dispatches the timed event one more time before stopping.
keyboard = new EasyKeyboard(stage);
keyboard.addEasyTimedListener("A", 1000, function() { trace("Key A is pressed!!") }, true, "key1");
keyboard.addEasyListener("S", function () { keyboard.removeListener("key1"); trace("Listener for A key removed!"); } );
Lets fix this. Update the removeListener() function:
/**
* Remove a single listener.
* @paramlistenerId Id of the listener, which is specified as String when the listener is created.
*/
public function removeListener(listenerId:String):void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i].id == listenerId) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
break;
}
}
}
Now well add a function which removes all the listeners at once. Right now we have one called kill(), but it didnt actually remove all the listeners from the array - it just stops listening to the keyboard as a whole.
The removeAllListeners() method will loop through all listeners and remove them one by one, also taking care of timers the same way like in removeListener:
/**
* Remove all listeners. IMPORATNT: If you are removing the EasyKeyboard object as a whole, use the kill() method.
*/
public function removeAllListeners():void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
}
}
We should also call this function in kill():
/**
* Call this before nullifying the class instance to remove all the listeners.
*/
public function kill():void {
removeAllListeners();
st.removeEventListener(KeyboardEvent.KEY_DOWN, kDown);
st.removeEventListener(KeyboardEvent.KEY_UP, kUp);
st.addEventListener(Event.ENTER_FRAME, frame);
}
So, to remove all the listeners, the user simply writes:
keyboard.removeAllListeners();
Full EasyKeyboard.as class code so far:
package com.kircode.EasyKeyboard
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.utils.Timer;
/**
* Utility for easy keyboard listener management.
* @author Kirill Poletaev
*/
public class EasyKeyboard
{
public var listeners:Array = [];
private var keyLabels:Array = ["0","1","2","3","4","5","6","7","Backspace","Tab","10","11","Center","Enter","14","15","Shift","Control","Alt","Pause","Caps Lock","21","22","23","24","25","26","27","28","29","30","31","Space","Page Up","Page Down","End","Home","Left","Up","Right","Down","41","42","43","44","Insert","Delete","47","0","1","2","3","4","5","6","7","8","9","58","59","60","61","62","63","64","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Windows","Windows","Menu","94","95","Num 0","Num 1","Num 2","Num 3","Num 4","Num 5","Num 6","Num 7","Num 8","Num 9","Num *","Num +","108","Num -","Num .","Num /","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","Num Lock","Scroll Lock","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185",";","+",",","-",".","/","~","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","[","\","]","","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254","255"];
private var st:Stage;
public function EasyKeyboard(stage:Stage)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, kDown);
stage.addEventListener(KeyboardEvent.KEY_UP, kUp);
stage.addEventListener(Event.ENTER_FRAME, frame);
st = stage;
}
private function frame(evt:Event):void {
for (var i:int = 0; i < listeners.length; i++) {
if (listeners[i] is HoldListener && listeners[i].flag) {
if (listeners[i].handler != null) listeners[i].handler.call();
}
}
}
/**
* Call this before nullifying the class instance to remove all the listeners.
*/
public function kill():void {
removeAllListeners();
st.removeEventListener(KeyboardEvent.KEY_DOWN, kDown);
st.removeEventListener(KeyboardEvent.KEY_UP, kUp);
st.addEventListener(Event.ENTER_FRAME, frame);
}
/**
* Add event listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addListener(keyCode:int, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false, id:String = ""):void {
listeners.push(new KeyListener(keyCode, handlerDown, handlerUp, alt, ctrl, shift, id));
}
/**
* Add event listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramhandler Function to execute while the key is held every frame.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addHoldListener(keyCode:int, handler:Function, id:String = ""):void {
listeners.push(new HoldListener(keyCode, handler, false, id));
}
/**
* Add event listener for a combination of keys using key codes.
* @paramkeyCodes Array of key codes for the combination.
* @paramhandler Function to execute when the combination is held.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addComboListener(keyCodes:Array, handler:Function, id:String = ""):void {
var flags:Array = [];
for (var i:int = 0; i < keyCodes.length; i++) {
if (isNaN(keyCodes[i])) {
throw new Error(Incorrect key code value specified - " + keyCodes[i] + " is not a number.);
return;
}
flags.push(false);
}
listeners.push(new ComboListener(keyCodes, handler, flags, id));
}
/**
* Add event timed listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramdelay Delay in milliseconds of how long the key needs to be held down for the event to be registered.
* @paramhandler Function to execute when the key has been held for the specified amount of time.
* @paramrepeat Set to true if you want to dispatch the event forever until the key is released. If you only want to dispatch it once, set to false.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addTimedListener(keyCode:int, delay:int, handler:Function, repeat:Boolean = true, id:String = ""):void {
var rep:int = 1;
if (repeat == true) rep = 0;
var delayTimer:Timer = new Timer(delay, 1);
listeners.push(new TimedListener(keyCode, delayTimer, handler, rep, id));
}
/**
* Add event listener for a sequence of keys to be pressed.
* @paramkeyCodes Array of key codes in the sequence.
* @paramhandler Function to execute when the keys are pressed in the specific order.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addSequenceListener(keyCodes:Array, handler:Function, id:String = ""):void {
for (var i:int = 0; i < keyCodes.length; i++) {
if (isNaN(keyCodes[i])) {
throw new Error(Incorrect key code value specified - " + keyCodes[i] + " is not a number.);
return;
}
}
listeners.push(new SequenceListener(keyCodes, handler, id));
}
/**
* Add event listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addEasyListener(keyName:String, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false, id:String = ""):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addListener(code, handlerDown, handlerUp, alt, ctrl, shift, id);
}
/**
* Add hold listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandler Function to execute while the key is held every frame.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addEasyHoldListener(keyName:String, handler:Function, id:String = ""):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addHoldListener(code, handler, id);
}
/**
* Add event listener for a combination of keys using key names.
* @paramkeyNames Array of key names for the combination.
* @paramhandler Function to execute when the combination is held.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addEasyComboListener(keyNames:Array, handler:Function, id:String = ""):void {
var flags:Array = [];
var keyCodes:Array = [];
var u:int;
var i:int;
var code:int = -1;
var keyName:String;
for (u = 0; u < keyNames.length; u++) {
flags.push(false);
code = -1;
keyName = keyNames[u];
for (i = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
keyCodes.push(code);
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
}
listeners.push(new ComboListener(keyCodes, handler, flags, id));
}
/**
* Add event listener for a sequence of keys to be pressed using key names.
* @paramkeyNames Array of key names in the sequence.
* @paramhandler Function to execute when the keys are pressed in the specific order.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addEasySequenceListener(keyNames:Array, handler:Function, id:String = ""):void {
var keyCodes:Array = [];
var u:int;
var i:int;
var code:int = -1;
var keyName:String;
for (u = 0; u < keyNames.length; u++) {
code = -1;
keyName = keyNames[u];
for (i = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
keyCodes.push(code);
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
}
listeners.push(new SequenceListener(keyCodes, handler, id));
}
/**
* Add event timed listener for a single key using a keyname.
* @paramkeyName Name of the key.
* @paramdelay Delay in milliseconds of how long the key needs to be held down for the event to be registered.
* @paramhandler Function to execute when the key has been held for the specified amount of time.
* @paramrepeat Set to true if you want to dispatch the event forever until the key is released. If you only want to dispatch it once, set to false.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/
public function addEasyTimedListener(keyName:String, delay:int, handler:Function, repeat:Boolean = true, id:String = ""):void {
var rep:int = 1;
if (repeat == true) rep = 0;
var delayTimer:Timer = new Timer(delay, 1);
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
listeners.push(new TimedListener(code, delayTimer, handler, rep, id));
}
private function kDown(evt:KeyboardEvent):void {
var u:int = 0;
var comboKeys:int = 0;
for (var i:int = 0; i < listeners.length; i++) {
if (listeners[i] is KeyListener && evt.keyCode == listeners[i].keyCode && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerD) listeners[i].handlerD.call();
}
if (listeners[i] is HoldListener && evt.keyCode == listeners[i].keyCode) {
listeners[i].flag = true;
}
if (listeners[i] is ComboListener) {
comboKeys = 0;
for (u = 0; u < listeners[i].keyCodes.length; u++) {
if (listeners[i].keyCodes[u] == evt.keyCode) {
listeners[i].flags[u] = true;
}
if (listeners[i].flags[u] == true) comboKeys++;
}
if (comboKeys == listeners[i].keyCodes.length) {
if (listeners[i].handler) listeners[i].handler.call();
}
}
if (listeners[i] is TimedListener && evt.keyCode == listeners[i].keyCode) {
if (!listeners[i].delayTimer.running) {
listeners[i].delayTimer.start();
}
}
if (listeners[i] is SequenceListener) {
if (evt.keyCode == listeners[i].keyCodes[listeners[i].sequenceIndex]) {
listeners[i].sequenceIndex++;
if (listeners[i].sequenceIndex == listeners[i].keyCodes.length) {
if (listeners[i].handler) listeners[i].handler.call();
listeners[i].sequenceIndex = 0;
}
}else {
listeners[i].sequenceIndex = 0;
}
}
}
}
private function kUp(evt:KeyboardEvent):void {
var u:int = 0;
for (var i:int = 0; i < listeners.length; i++) {
if (listeners[i] is KeyListener && evt.keyCode == listeners[i].keyCode && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerU) listeners[i].handlerU.call();
}
if (listeners[i] is HoldListener && evt.keyCode == listeners[i].keyCode) {
listeners[i].flag = false;
}
if (listeners[i] is ComboListener) {
for (u = 0; u < listeners[i].keyCodes.length; u++) {
if (listeners[i].keyCodes[u] == evt.keyCode) {
listeners[i].flags[u] = false;
}
}
}
if (listeners[i] is TimedListener && evt.keyCode == listeners[i].keyCode) {
if (listeners[i].delayTimer.running) {
listeners[i].delayTimer.reset();
if (listeners[i].repeat == 2) listeners[i].repeat = 1;
}
}
}
}
/**
* Remove a single listener.
* @paramlistenerId Id of the listener, which is specified as String when the listener is created.
*/
public function removeListener(listenerId:String):void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i].id == listenerId) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
break;
}
}
}
/**
* Remove all listeners. IMPORATNT: If you are removing the EasyKeyboard object as a whole, use the kill() method.
*/
public function removeAllListeners():void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
}
}
}
}
Thanks for reading!
Friday, January 23, 2015
AdvAlert AS3 class Download and How To Use Part 6
Here you can find a couple of AdvAlert window skin examples that you can use in your games and applications.
Below are 4 skins I made that you can use in your AdvAlert powered alert windows. To implement them, use the the code below each example image.




Now you see what can be achieved with just a few lines of code and AdvAlert!
If you make any cool skins yourself and want to share them with others, post the code in the comments below!
Thanks for reading!
Read more »
Below are 4 skins I made that you can use in your AdvAlert powered alert windows. To implement them, use the the code below each example image.

var mySkin:AdvAlertSkin = new AdvAlertSkin();
mySkin.bgRect = new SolidColorRect(0xe2e2e2, [5, 5, 5, 5], 1);
mySkin.bgStroke = new SolidColorStroke(1, 0x000000, 0);
mySkin.headerHeight = 34;
mySkin.headerRect = new SolidColorRect(0x99ccff, [5, 5, 0, 0], 1);
mySkin.headerPadding = new TextPadding(0, 0, 0, 0);
mySkin.titleFormat = new TextFormat("Verdana", 22, 0xffffff);
mySkin.titleFilters = [new DropShadowFilter(1, 45, 0x000000, 0.7, 0, 0)];
mySkin.textFormat = new TextFormat("Verdana", 15, 0x111111);
mySkin.blurColor = 0x000000;
mySkin.buttonbarPadding.bottom = 0;
var myButtonSkin:AdvAlertButtonSkin = new AdvAlertButtonSkin();
myButtonSkin.bgRect = new SolidColorRect(0x99ccff, [5, 5, 0, 0], 1);
myButtonSkin.bgStroke = new SolidColorStroke(1, 0x000000, 0);
myButtonSkin.textFormat = new TextFormat("Verdana", 17, 0xffffff, null, null, null, null, null, "center" );
myButtonSkin.textFilters = [new DropShadowFilter(1, 45, 0x000000, 0.7, 0, 0)];
myButtonSkin.hover_bgRect = new SolidColorRect(0x7799bb, [5, 5, 0, 0], 1);
myButtonSkin.hover_bgStroke = new SolidColorStroke(1, 0x000000, 0);
myButtonSkin.hover_textFormat = new TextFormat("Verdana", 17, 0xffffff, null, null, null, null, null, "center" );
myButtonSkin.hover_textFilters = [new DropShadowFilter(1, 45, 0x000000, 0.7, 0, 0)];
AlertManager = new AdvAlertManager(this, stage, mySkin, myButtonSkin, null, true, 400);
var myAlert:AdvAlertWindow = AlertManager.alert("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", "Title", [new AdvAlertButton("OK"), new AdvAlertButton("Cancel")]);

var mySkin:AdvAlertSkin = new AdvAlertSkin();
var bgMatrix:Matrix = new Matrix();
bgMatrix.createGradientBox(200, 200, 1.57, 100, 100);
mySkin.bgRect = new GradientColorRect(GradientType.LINEAR, [0x000000, 0x444444], [1, 1], [0, 255], bgMatrix, "pad", "rgb", 0, [0, 0, 0, 0]);
mySkin.bgStroke = new SolidColorStroke(2, 0xeeeeee);
mySkin.headerRect = new SolidColorRect(0x000000, null, 0);
mySkin.headerPadding = new TextPadding(5, 0, 0, 0);
mySkin.titleFormat.align = "center";
mySkin.titleFormat.size = 22;
var myButtonSkin:AdvAlertButtonSkin = new AdvAlertButtonSkin();
myButtonSkin.bgRect = new SolidColorRect(0xffffff, [0,0,0,0], 1);
myButtonSkin.bgStroke = new SolidColorStroke(0, 0, 0);
myButtonSkin.textFormat.bold = true;
myButtonSkin.textFormat.color = 0x000000;
myButtonSkin.hover_bgRect = new SolidColorRect(0x000000, [0,0,0,0], 1);
myButtonSkin.hover_bgStroke = new SolidColorStroke(0, 0, 0);
myButtonSkin.hover_textFormat.bold = true;
myButtonSkin.hover_textFormat.color = 0xf;
AlertManager = new AdvAlertManager(this, stage, mySkin, myButtonSkin, null, true, 400);
var myAlert:AdvAlertWindow = AlertManager.alert("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", "Title", [new AdvAlertButton("OK"), new AdvAlertButton("Cancel")]);

var mySkin:AdvAlertSkin = new AdvAlertSkin();
var bgData:BitmapData = new BitmapData(400, 200, false, 0xffffffff);
bgData.perlinNoise(100, 100, 4, 218, true, true, 1, false);
mySkin.bgRect = new BitmapRect(bgData, null, true, false, [10, 10, 10, 10]);
mySkin.bgStroke = new SolidColorStroke(3, 0x440000, 1);
mySkin.headerRect = new SolidColorRect(0x000000, [10, 10, 10, 10], 0.5);
mySkin.headerHeight = 40;
mySkin.titleFormat.size = 30;
mySkin.titleFormat.align = "center";
mySkin.buttonbarAlign = "center";
mySkin.blurColor = 0x0;
var myButtonSkin:AdvAlertButtonSkin = new AdvAlertButtonSkin();
myButtonSkin.bgRect = new SolidColorRect(0x000000, [10, 10, 10, 10], 0.5);
myButtonSkin.bgStroke = new SolidColorStroke (1, 0x000000, 0);
myButtonSkin.w = 100;
myButtonSkin.hover_bgRect = new SolidColorRect(0xff0000, [10, 10, 10, 10], 0.5);
myButtonSkin.hover_bgStroke = new SolidColorStroke (1, 0x000000, 0);
myButtonSkin.hover_w = 100;
AlertManager = new AdvAlertManager(this, stage, mySkin, myButtonSkin, null, true, 400);
var myAlert:AdvAlertWindow = AlertManager.alert("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", "Title", [new AdvAlertButton("OK"), new AdvAlertButton("Cancel")]);

var mySkin:AdvAlertSkin = new AdvAlertSkin();
mySkin.bgRect = new SolidColorRect(0xffffff, [0,0,0,0], 1);
mySkin.bgStroke = new SolidColorStroke(2, 0x000000, 1);
mySkin.headerRect = new SolidColorRect(0xaaffaa, [0, 0, 0, 0], 1);
mySkin.headerStroke = new SolidColorStroke(1, 0x555555, 1);
mySkin.textFormat.size = 13;
mySkin.titleFormat.size = 20;
mySkin.textFormat.color = 0x111111;
mySkin.titleFormat.color = 0x333333;
mySkin.titleFilters = [new DropShadowFilter(3, 45, 0xffffff, 1, 0, 0)];
mySkin.titleFormat.align = "center";
mySkin.filters = [new DropShadowFilter(8, 45, 0, 1, 0, 0)];
var myButtonSkin:AdvAlertButtonSkin = new AdvAlertButtonSkin();
myButtonSkin.bgRect = new SolidColorRect(0xaaffaa, [0, 0, 0, 0], 1);
myButtonSkin.bgStroke = new SolidColorStroke(1, 0x555555, 1);
myButtonSkin.w = 110;
myButtonSkin.textFormat.color = 0x000000;
myButtonSkin.textFilters = [new DropShadowFilter(3, 45, 0xffffff, 1, 0, 0)];
myButtonSkin.hover_bgRect = new SolidColorRect(0xffffff, [0, 0, 0, 0], 1);
myButtonSkin.hover_bgStroke = new SolidColorStroke(1, 0x555555, 1);
myButtonSkin.hover_w = 110;
myButtonSkin.hover_textFormat.color = 0x000000;
myButtonSkin.hover_textFilters = [new DropShadowFilter(3, 45, 0xffffff, 1, 0, 0)];
AlertManager = new AdvAlertManager(this, stage, mySkin, myButtonSkin, null, true, 400);
var myAlert:AdvAlertWindow = AlertManager.alert("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", "Title", [new AdvAlertButton("OK"), new AdvAlertButton("Cancel")]);
Now you see what can be achieved with just a few lines of code and AdvAlert!
If you make any cool skins yourself and want to share them with others, post the code in the comments below!
Thanks for reading!
Creating EasyTooltip class Part 13
In this tutorial we will add the ability to set a tooltip invoke delay - the tooltip will only be displayed after the user has held their mouse over the object for a specific period of time.
First of all, go to the EasyTooltip class and add a new parameter in the constructor - spawnDelay. Declare a variable in the class called "delay", and in the constructor apply spawnDelays value to delay. Then, in the addListener() function, pass the delay value as third parameter of the TooltipListener constructor:
Go to TooltipListener class, declare a Timer:
Receive the delay in the constructor, apply its value as the delay of the timer when creating it. Add a TIMER_COMPLETE event listener to the timer.
In the onOver() function, instead of simply setting display property of the tooltip to true, reset and start the timer:
In the onOut() function, set display to false and stop the timer:
And create the timer handler function onTimer(), use it to set display property of the tooltip to true:
This way the tooltip will be displayed after the timer dispatches the TIMER_COMPLETE event. Full TooltipListener class code:
In the main.as file, you can now pass a value in milliseconds to the EasyTooltip constructor to set the delay:
Thanks for reading!
Read more »
First of all, go to the EasyTooltip class and add a new parameter in the constructor - spawnDelay. Declare a variable in the class called "delay", and in the constructor apply spawnDelays value to delay. Then, in the addListener() function, pass the delay value as third parameter of the TooltipListener constructor:
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;
/**
* 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.
* @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, spawnDelay:int = 0)
{
delay = spawnDelay;
par = parent;
listeners = [];
parW = parentWidth;
parH = parentHeight;
cursor = new TooltipCursor(parentWidth, parentHeight);
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.y = par.mouseY;
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);
}
}
}
}
Go to TooltipListener class, declare a Timer:
private var timer:Timer;
Receive the delay in the constructor, apply its value as the delay of the timer when creating it. Add a TIMER_COMPLETE event listener to the timer.
public function TooltipListener(listener:DisplayObject, tooltip:Tooltip, delay:int)
{
list = listener;
tip = tooltip;
timer = new Timer(delay, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
listener.addEventListener(MouseEvent.ROLL_OVER, onOver);
listener.addEventListener(MouseEvent.ROLL_OUT, onOut);
}
In the onOver() function, instead of simply setting display property of the tooltip to true, reset and start the timer:
private function onOver(evt:MouseEvent):void {
timer.reset();
timer.start();
}
In the onOut() function, set display to false and stop the timer:
private function onOut(evt:MouseEvent):void {
tip.display = false;
timer.stop();
}
And create the timer handler function onTimer(), use it to set display property of the tooltip to true:
private function onTimer(evt:TimerEvent):void {
tip.display = true;
}
This way the tooltip will be displayed after the timer dispatches the TIMER_COMPLETE event. Full TooltipListener class code:
package com.kircode.EasyTooltip
{
import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
/**
* Manages a single visible object that displays a tooltip when rolled over.
* @author Kirill Poletaev
*/
public class TooltipListener
{
public var tip:Tooltip;
public var list:DisplayObject;
private var timer:Timer;
public function TooltipListener(listener:DisplayObject, tooltip:Tooltip, delay:int)
{
list = listener;
tip = tooltip;
timer = new Timer(delay, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
listener.addEventListener(MouseEvent.ROLL_OVER, onOver);
listener.addEventListener(MouseEvent.ROLL_OUT, onOut);
}
public function kill():void {
list.removeEventListener(MouseEvent.ROLL_OVER, onOver);
list.removeEventListener(MouseEvent.ROLL_OUT, onOut);
}
private function onOver(evt:MouseEvent):void {
timer.reset();
timer.start();
}
private function onOut(evt:MouseEvent):void {
tip.display = false;
timer.stop();
}
private function onTimer(evt:TimerEvent):void {
tip.display = true;
}
}
}
In the main.as file, you can now pass a value in milliseconds to the EasyTooltip constructor to set the delay:
var myStyle:TooltipStyle = new TooltipStyle();
myStyle.minWidth = 240;
myStyle.maxWidth = 300;
myStyle.offsetX = -10;
myStyle.offsetY = -10;
tooltip = new EasyTooltip(stage, stage.stageWidth, stage.stageHeight, 500);
tooltip.setStyle(myStyle);
tooltip.addListener(object1, "This is a piece of a longer text. It should fit in the visible area.");
Thanks for reading!
Thursday, January 22, 2015
Creating Advanced Alert Window class Part 39
In this tutorial we will add the ability to add default button index for alert windows (for tab navigation), as well as improve the tab navigation itself.
By adding a default button index I mean setting an index of the button that the developer wants to be selected by default. So, if the alert pops up and the user simply presses Enter on his keyboard, the default button is pressed. The default index is 0 by default (which represents the first button in the array).
There are a few things we need to keep in mind while implementing the feature.
The first important thing is that when there are more than 1 alert windows present, when the user closes the first one, we need to update the new button index (focusedButton variable) according to the next windows default button index.
The second thing is related to how we handle tab navigation. Right now the kDown function increases focusedButton by 1 and executes all the code in it using that value, which is why we have focusedButton set to -1 by default (-1 + 1 = 0, and 0 is the index we want to start with). Were going to modify the code, so that the focusedButton value is increased by 1 ONLY if there is a button in the window, which has "over" property set to true.
This means, that if the default button index is 1 (second button), and there are no buttons currently rolled over or selected using tab, if the user presses Enter - the second button is pressed. If they press Tab, the second button is selected, instead of third, so that the user can see what button is highlighted and press enter again to press it.
So, as long as nothing is initially selected: pressing Enter = pressing Tab and then Enter.
This makes the navigation more user-friendly and intuitive.
Lets get started. Go to AdvAlertManager class, find the alert() function and add a new parameter to it right after the buttons one - defaultButton:int = 0.
Add a new parameter to the object that is added to the windows array in alert() function - set the attribute name to defButton and the value to defaultButton:
In the same function set focusedButton to defaultButton:
Full function:
Go to kDown() function. Inside the keyCode==9 if...statement add 2 variables - needIncrease and i.
Set needIncrease to false by default. Then loop through all buttons, and if at least one button has its over property set to true - set needIncrease to true.
Check if needIncrease is true, if so - increase focusedButton by 1.
Now go to closeWindow() function. Remove the line that sets focusedButton to -1, instead add a new line to windows.length>0 if...statement and set focusedButton to the defButton value of the next window:
And thats it!
Full AdvAlertManager class code:
Now you acn go to main.as and try this code, which creates 2 windows with 3 buttons each, but different default indices. If you just press enter (or tab and then enter), youll see that different buttons are selected by default in each window.
Thanks for reading!
Read more »
By adding a default button index I mean setting an index of the button that the developer wants to be selected by default. So, if the alert pops up and the user simply presses Enter on his keyboard, the default button is pressed. The default index is 0 by default (which represents the first button in the array).
There are a few things we need to keep in mind while implementing the feature.
The first important thing is that when there are more than 1 alert windows present, when the user closes the first one, we need to update the new button index (focusedButton variable) according to the next windows default button index.
The second thing is related to how we handle tab navigation. Right now the kDown function increases focusedButton by 1 and executes all the code in it using that value, which is why we have focusedButton set to -1 by default (-1 + 1 = 0, and 0 is the index we want to start with). Were going to modify the code, so that the focusedButton value is increased by 1 ONLY if there is a button in the window, which has "over" property set to true.
This means, that if the default button index is 1 (second button), and there are no buttons currently rolled over or selected using tab, if the user presses Enter - the second button is pressed. If they press Tab, the second button is selected, instead of third, so that the user can see what button is highlighted and press enter again to press it.
So, as long as nothing is initially selected: pressing Enter = pressing Tab and then Enter.
This makes the navigation more user-friendly and intuitive.
Lets get started. Go to AdvAlertManager class, find the alert() function and add a new parameter to it right after the buttons one - defaultButton:int = 0.
public function alert(text:String, title:String = "", buttons:Array = null, defaultButton:int = 0, closeHandler:Function = null, width:int = 0, height:int = 0, position:Point = null, minHeight:int = 0, maxHeight:int = 0, maxWidth:int = 0, horizontalStretch:Boolean = true, openSound:Sound = null):AdvAlertWindow {
Add a new parameter to the object that is added to the windows array in alert() function - set the attribute name to defButton and the value to defaultButton:
windows.push( {window:w, blur:b, onclose:closeHandler, defButton:defaultButton} );
In the same function set focusedButton to defaultButton:
focusedButton = defaultButton;
Full function:
/**
* Create an alert window.
* @paramtext Text value of the alert window.
* @paramtitle Title value of the alert window.
* @parambuttons (Optional) Array of AdvAlertButton objects that represent buttons in the alert window.
* @paramdefaultButton (Optional) Index of the default button (used for tab navigation).
* @paramcloseHandler (Optional) Close handling function. Must receive a string value as parameter (which will hold the label of the button that was clicked).
* @paramwidth (Optional) Width of the alert window. If 0, set to default.
* @paramheight (Optional) Height of the alert window. If 0, set to default. If default is 0, window will be auto sized.
* @paramposition (Optional) Coordinates of top-left corner of the alert window. If not specified - the window is centered.
* @paramminHeight (Optional) The minimum height value of the alert window. If 0, set to default.
* @parammaxHeight (Optional) The maximum height value of the alert window. If 0, set to default.
* @parammaxWidth (Optional) The maximum width value of the alert window. If 0, set to default.
* @paramhorizontalStretch (Optional) If set to true, will stretch the window horizontally if the text doesnt fit and the height has already reached maxHeight.
* @paramopenSound (Optional) Sound to play when the window opens. Specified default sound plays by default.
*/
public function alert(text:String, title:String = "", buttons:Array = null, defaultButton:int = 0, closeHandler:Function = null, width:int = 0, height:int = 0, position:Point = null, minHeight:int = 0, maxHeight:int = 0, maxWidth:int = 0, horizontalStretch:Boolean = true, openSound:Sound = null):AdvAlertWindow {
if (width == 0) width = defWidth;
if (height == 0) height = defHeight;
if (minHeight == 0) minHeight = defMinHeight;
if (maxHeight == 0) maxHeight = defMaxHeight;
if (maxWidth == 0) maxWidth = defMaxWidth;
if (openSound != null) {
openSound.play();
}else
if (openingSound != null) {
openingSound.play();
}
if (position == null) position = new Point((pWidth / 2) - (width / 2), (pHeight / 2) - (height / 2));
if (buttons == null) buttons = [new AdvAlertButton("OK")];
for (var i:int = buttons.length - 1; i >= 0; i--) {
if (!buttons[i] is AdvAlertButton) {
throw new Error("An item in buttons array is not an AdvAlertButton instance. Ignoring...");
buttons.splice(i, 1);
}else {
buttons[i].addEventListener(MouseEvent.CLICK, buttonHandler);
}
}
var w:AdvAlertWindow = new AdvAlertWindow(text, title, width, height, position, skin, buttons, bSkin, pWidth, pHeight, minHeight, maxHeight, maxWidth, horizontalStretch);
var b:AdvAlertBlur = new AdvAlertBlur(pWidth, pHeight, skin);
var currentIndex:int = windows.length;
windows.push( {window:w, blur:b, onclose:closeHandler, defButton:defaultButton} );
defaultContainer.addChild(b);
defaultContainer.addChild(w);
topWindow = w;
focusedButton = defaultButton;
if (tabDisable) {
defaultContainer.tabChildren = false;
defaultContainer.tabEnabled = false;
}
function buttonHandler(evt:MouseEvent):void {
closeWindow(currentIndex, closeHandler, evt.currentTarget as AdvAlertButton);
}
return w;
}
Go to kDown() function. Inside the keyCode==9 if...statement add 2 variables - needIncrease and i.
Set needIncrease to false by default. Then loop through all buttons, and if at least one button has its over property set to true - set needIncrease to true.
Check if needIncrease is true, if so - increase focusedButton by 1.
private function kDown(evt:KeyboardEvent):void {
if(tabDisable){
if (evt.keyCode == 9 && topWindow != null && topWindow.buttons.length > 0) {
var needIncrease:Boolean = false;
var i:int;
for (i = 0; i < topWindow.buttons.length; i++) {
if (topWindow.buttons[i].over == true) needIncrease = true;
}
if (needIncrease) focusedButton++;
if (focusedButton >= topWindow.buttons.length) {
focusedButton = 0;
}
for (i = 0; i < topWindow.buttons.length; i++) {
topWindow.buttons[i].over = false;
topWindow.buttons[i].updateDraw();
}
topWindow.buttons[focusedButton].over = true;
topWindow.buttons[focusedButton].updateDraw();
}
if (evt.keyCode == 13 && topWindow != null && topWindow.buttons.length > 0) {
var currentIndex:int = windows.length - 1;
var closeHandler:Function = windows[currentIndex].onclose;
closeWindow(currentIndex, closeHandler, topWindow.buttons[focusedButton]);
}
}
}
Now go to closeWindow() function. Remove the line that sets focusedButton to -1, instead add a new line to windows.length>0 if...statement and set focusedButton to the defButton value of the next window:
private function closeWindow(currentIndex:int, closeHandler:Function, currentButton:AdvAlertButton):void {
if (closeHandler != null && currentButton != null) closeHandler.call(currentButton, currentButton.txt);
windows[currentIndex].window.parent.removeChild(windows[currentIndex].window);
windows[currentIndex].blur.parent.removeChild(windows[currentIndex].blur);
windows.splice(currentIndex, 1);
if (windows.length > 0) {
focusedButton = windows[windows.length - 1].defButton;
topWindow = windows[windows.length - 1].window;
}
if (windows.length == 0) topWindow = null;
if (tabDisable && windows.length==0) {
defaultContainer.tabChildren = true;
defaultContainer.tabEnabled = true;
}
}
And thats it!
Full AdvAlertManager class code:
package com.kircode.AdvAlert
{
import flash.display.DisplayObjectContainer;
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.media.Sound;
/**
* 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;
private var bSkin:AdvAlertButtonSkin;
private var tabDisable:Boolean;
private var topWindow:AdvAlertWindow;
private var focusedButton:int;
private var stg:Stage;
private var openingSound:Sound;
private var defWidth:int;
private var defHeight:int;
private var defMinHeight:int;
private var defMaxHeight:int;
private var defMaxWidth:int;
/**
* AdvAlertManager constructor.
* @paramdefaultWindowContainer Parent container of alert windows.
* @paramstage Stage reference.
* @paramwindowSkin Default skin for alert windows.
* @parambuttonSkin Default skin for buttons in this window.
* @paramopenSound Default window open sound.
* @paramdisableTab Disable tab focusing on the parent container when an alert window is visible. This also enables tab navigation for the alert windows buttons.
* @paramdefaultWidth Set default width for all window alerts. 300 by default.
* @paramdefaultHeight Set default height for all window alerts. 0 by default. If 0, the window is auto-sized based on the text length.
* @paramdefaultMinHeight Set default minimal height for all window alerts. 0 by default.
* @paramdefaultMaxHeight Set default maximal height for all window alerts. 0 by default. If 0, automatically set to the height of the stage.
* @paramdefaultMaxWidth Set default maximal width for all window alerts. 0 by default. If 0, automatically set to the width of the stage.
*/
public function AdvAlertManager(defaultWindowContainer:DisplayObjectContainer, stage:Stage, windowSkin:AdvAlertSkin = null, buttonSkin:AdvAlertButtonSkin = null, openSound:Sound = null, disableTab:Boolean = true, defaultWidth:int = 300, defaultHeight:int = 0, defaultMinHeight:int = 0, defaultMaxHeight:int = 0, defaultMaxWidth:int = 0)
{
defWidth = defaultWidth;
defHeight = defaultHeight;
defMinHeight = defaultMinHeight;
defMaxHeight = defaultMaxHeight;
defMaxWidth = defaultMaxWidth;
if (defMaxHeight == 0) defMaxHeight = stage.stageHeight;
if (defMaxWidth == 0) defMaxWidth = stage.stageWidth;
openingSound = openSound;
skin = windowSkin;
bSkin = buttonSkin;
tabDisable = disableTab;
if (skin == null) skin = new AdvAlertSkin();
if (bSkin == null) bSkin = new AdvAlertButtonSkin();
defaultContainer = defaultWindowContainer;
pWidth = stage.stageWidth;
pHeight = stage.stageHeight;
stg = stage;
windows = [];
stg.addEventListener(KeyboardEvent.KEY_DOWN, kDown);
}
private function kDown(evt:KeyboardEvent):void {
if(tabDisable){
if (evt.keyCode == 9 && topWindow != null && topWindow.buttons.length > 0) {
var needIncrease:Boolean = false;
var i:int;
for (i = 0; i < topWindow.buttons.length; i++) {
if (topWindow.buttons[i].over == true) needIncrease = true;
}
if (needIncrease) focusedButton++;
if (focusedButton >= topWindow.buttons.length) {
focusedButton = 0;
}
for (i = 0; i < topWindow.buttons.length; i++) {
topWindow.buttons[i].over = false;
topWindow.buttons[i].updateDraw();
}
topWindow.buttons[focusedButton].over = true;
topWindow.buttons[focusedButton].updateDraw();
}
if (evt.keyCode == 13 && topWindow != null && topWindow.buttons.length > 0) {
var currentIndex:int = windows.length - 1;
var closeHandler:Function = windows[currentIndex].onclose;
closeWindow(currentIndex, closeHandler, topWindow.buttons[focusedButton]);
}
}
}
/**
* Close the top alert window.
*/
public function closeLast():void {
var currentIndex:int = windows.length - 1;
var closeHandler:Function = windows[currentIndex].onclose;
closeWindow(currentIndex, closeHandler, null);
}
private function closeWindow(currentIndex:int, closeHandler:Function, currentButton:AdvAlertButton):void {
if (closeHandler != null && currentButton != null) closeHandler.call(currentButton, currentButton.txt);
windows[currentIndex].window.parent.removeChild(windows[currentIndex].window);
windows[currentIndex].blur.parent.removeChild(windows[currentIndex].blur);
windows.splice(currentIndex, 1);
if (windows.length > 0) {
focusedButton = windows[windows.length - 1].defButton;
topWindow = windows[windows.length - 1].window;
}
if (windows.length == 0) topWindow = null;
if (tabDisable && windows.length==0) {
defaultContainer.tabChildren = true;
defaultContainer.tabEnabled = true;
}
}
/**
* Set skin of all future created alert windows.
* @paramwindowSkin Reference to an AdvAlertSkin object.
*/
public function setSkin(windowSkin:AdvAlertSkin):void {
skin = windowSkin;
}
/**
* Set skin of all buttons of future created alert windows.
* @parambuttonSkin Reference to an AdvAlertButtonSkin object.
*/
public function setButtonSkin(buttonSkin:AdvAlertButtonSkin):void {
bSkin = buttonSkin;
}
/**
* Set new options for the alert manager object - has the same parameters as the constructor.
* @paramdefaultWindowContainer Parent container of alert windows.
* @paramstage Stage reference.
* @paramwindowSkin Default skin for alert windows.
* @parambuttonSkin Default skin for buttons in this window.
* @paramopenSound Default window open sound.
* @paramdisableTab Disable tab focusing on the parent container when an alert window is visible. This also enables tab navigation for the alert windows buttons.
* @paramdefaultWidth Set default width for all window alerts. 300 by default.
* @paramdefaultHeight Set default height for all window alerts. 0 by default. If 0, the window is auto-sized based on the text length.
* @paramdefaultMinHeight Set default minimal height for all window alerts. 0 by default.
* @paramdefaultMaxHeight Set default maximal height for all window alerts. 0 by default. If 0, automatically set to the height of the parent.
* @paramdefaultMaxWidth Set default maximal width for all window alerts. 0 by default. If 0, automatically set to the width of the stage.
*/
public function reset(defaultWindowContainer:DisplayObjectContainer, stage:Stage, windowSkin:AdvAlertSkin = null, buttonSkin:AdvAlertButtonSkin = null, openSound:Sound = null, disableTab:Boolean = true, defaultWidth:int = 300, defaultHeight:int = 0, defaultMinHeight:int = 0, defaultMaxHeight:int = 0, defaultMaxWidth:int = 0)
{
defWidth = defaultWidth;
defHeight = defaultHeight;
defMinHeight = defaultMinHeight;
defMaxHeight = defaultMaxHeight;
defMaxWidth = defaultMaxWidth;
if (defMaxHeight == 0) defMaxHeight = stage.stageHeight;
if (defMaxWidth == 0) defMaxWidth = stage.stageWidth;
openingSound = openSound;
skin = windowSkin;
bSkin = buttonSkin;
tabDisable = disableTab;
if (skin == null) skin = new AdvAlertSkin();
if (bSkin == null) bSkin = new AdvAlertButtonSkin();
defaultContainer = defaultWindowContainer;
pWidth = stage.stageWidth;
pHeight = stage.stageHeight;
stg = stage;
}
/**
* Create an alert window.
* @paramtext Text value of the alert window.
* @paramtitle Title value of the alert window.
* @parambuttons (Optional) Array of AdvAlertButton objects that represent buttons in the alert window.
* @paramdefaultButton (Optional) Index of the default button (used for tab navigation).
* @paramcloseHandler (Optional) Close handling function. Must receive a string value as parameter (which will hold the label of the button that was clicked).
* @paramwidth (Optional) Width of the alert window. If 0, set to default.
* @paramheight (Optional) Height of the alert window. If 0, set to default. If default is 0, window will be auto sized.
* @paramposition (Optional) Coordinates of top-left corner of the alert window. If not specified - the window is centered.
* @paramminHeight (Optional) The minimum height value of the alert window. If 0, set to default.
* @parammaxHeight (Optional) The maximum height value of the alert window. If 0, set to default.
* @parammaxWidth (Optional) The maximum width value of the alert window. If 0, set to default.
* @paramhorizontalStretch (Optional) If set to true, will stretch the window horizontally if the text doesnt fit and the height has already reached maxHeight.
* @paramopenSound (Optional) Sound to play when the window opens. Specified default sound plays by default.
*/
public function alert(text:String, title:String = "", buttons:Array = null, defaultButton:int = 0, closeHandler:Function = null, width:int = 0, height:int = 0, position:Point = null, minHeight:int = 0, maxHeight:int = 0, maxWidth:int = 0, horizontalStretch:Boolean = true, openSound:Sound = null):AdvAlertWindow {
if (width == 0) width = defWidth;
if (height == 0) height = defHeight;
if (minHeight == 0) minHeight = defMinHeight;
if (maxHeight == 0) maxHeight = defMaxHeight;
if (maxWidth == 0) maxWidth = defMaxWidth;
if (openSound != null) {
openSound.play();
}else
if (openingSound != null) {
openingSound.play();
}
if (position == null) position = new Point((pWidth / 2) - (width / 2), (pHeight / 2) - (height / 2));
if (buttons == null) buttons = [new AdvAlertButton("OK")];
for (var i:int = buttons.length - 1; i >= 0; i--) {
if (!buttons[i] is AdvAlertButton) {
throw new Error("An item in buttons array is not an AdvAlertButton instance. Ignoring...");
buttons.splice(i, 1);
}else {
buttons[i].addEventListener(MouseEvent.CLICK, buttonHandler);
}
}
var w:AdvAlertWindow = new AdvAlertWindow(text, title, width, height, position, skin, buttons, bSkin, pWidth, pHeight, minHeight, maxHeight, maxWidth, horizontalStretch);
var b:AdvAlertBlur = new AdvAlertBlur(pWidth, pHeight, skin);
var currentIndex:int = windows.length;
windows.push( {window:w, blur:b, onclose:closeHandler, defButton:defaultButton} );
defaultContainer.addChild(b);
defaultContainer.addChild(w);
topWindow = w;
focusedButton = defaultButton;
if (tabDisable) {
defaultContainer.tabChildren = false;
defaultContainer.tabEnabled = false;
}
function buttonHandler(evt:MouseEvent):void {
closeWindow(currentIndex, closeHandler, evt.currentTarget as AdvAlertButton);
}
return w;
}
}
}
Now you acn go to main.as and try this code, which creates 2 windows with 3 buttons each, but different default indices. If you just press enter (or tab and then enter), youll see that different buttons are selected by default in each window.
private function init(evt:Event):void {
var mySkin:AdvAlertSkin = new AdvAlertSkin();
mySkin.addContent(warning_icon, new Point(5, 40));
mySkin.textPadding.left = 140;
mySkin.titleFilters = [new DropShadowFilter(0, 0, 0, 1, 3, 3, 2, 3)];
mySkin.textFilters = [new DropShadowFilter(1, 45, 0, 0.4, 0, 0, 5, 1)];
var myButtonSkin:AdvAlertButtonSkin = new AdvAlertButtonSkin();
myButtonSkin.textFilters = [new DropShadowFilter(1, 45, 0, 0.4, 0, 0, 5, 1)];
myButtonSkin.hover_textFilters = [new DropShadowFilter(1, 45, 0, 0.4, 0, 0, 5, 1), new DropShadowFilter(0, 0, 0, 1, 3, 3, 1, 3)];
AlertManager = new AdvAlertManager(this, stage, mySkin, myButtonSkin);
AlertManager.alert("A window with 3 buttons. Default index: 1", "Example alert!", [new AdvAlertButton("One"), new AdvAlertButton("Two"), new AdvAlertButton("Three")], 1, onClose, 300, 200);
AlertManager.alert("A window with 3 buttons. Default index: 2", "Example alert!", [new AdvAlertButton("One"), new AdvAlertButton("Two"), new AdvAlertButton("Three")], 2, onClose, 300, 200);
}
private function onClose(str:String):void {
trace(str);
}
Thanks for reading!
Subscribe to:
Posts (Atom)