Wednesday, September 12, 2012

Creating Advanced Alert Window class: Part 10

In this tutorial we will improve our skinning system. We'll 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:

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 you'll 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 we'll add new types of stroke skinning in the next tutorials.

Thanks for reading!

No comments:

Post a Comment