Tuesday, September 18, 2012

Creating Advanced Alert Window class: Part 16

In this tutorial we continue working on our button bar.

First of all, go to AdvAlertButton.as class, and rename the _w and _h variables to just w and h. Make them public. The whole class should look like this:

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

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

public var w:Number = 80;
public var h:Number = 30;

public function AdvAlertButton() 
{
updateDraw();
}

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


}

}

Go to AdvAlertManager.as. Here we need to receive the buttons array, which consists of AdvAlertButton objects, and pass it to the AdvAlertWindow object. But what if an object is not an AdvAlertButton? We check if this happens, and throw an error, which warns the user that an item in the buttons array is not an AdvAlertButton instance. We delete this item from buttons array and repeat this check to all elements in the array.

This all happens in the alert() function:

public function alert(text:String, title:String = "", buttons:Array = null, width:int = 300, height:int = 200, position:Point = null):void {
if (position == null) position = new Point((pWidth / 2) - (width / 2), (pHeight / 2) - (height / 2));
if (buttons == null) buttons = [];
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);
}
}
var w:AdvAlertWindow = new AdvAlertWindow(text, title, width, height, position, skin, buttons);
var b:AdvAlertBlur = new AdvAlertBlur(pWidth, pHeight, skin);
windows.push( { window:w, blur:b } );
defaultContainer.addChild(b);
defaultContainer.addChild(w);

trace("Message: " + text);
}

Full AdvAlertManager.as class:

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

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

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

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

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

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

public function alert(text:String, title:String = "", buttons:Array = null, width:int = 300, height:int = 200, position:Point = null):void {
if (position == null) position = new Point((pWidth / 2) - (width / 2), (pHeight / 2) - (height / 2));
if (buttons == null) buttons = [];
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);
}
}
var w:AdvAlertWindow = new AdvAlertWindow(text, title, width, height, position, skin, buttons);
var b:AdvAlertBlur = new AdvAlertBlur(pWidth, pHeight, skin);
windows.push( { window:w, blur:b } );
defaultContainer.addChild(b);
defaultContainer.addChild(w);

trace("Message: " + text);
}

}

}

We will need to add a new property to AdvAlertSkin class - buttonInterval. Set it to 5 by default. The new AdvAlertSkin.as class:

package com.kircode.AdvAlert 
{
import flash.filters.DropShadowFilter;
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 var filters:Array;
public var blurColor:uint;
public var blurAlpha:Number;
public var buttonbarHeight:Number;
public var buttonbarPadding:TextPadding;
public var buttonInterval:Number;

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);
filters = [new DropShadowFilter(0, 0, 0, 1, 20, 20, 1, 3)];
blurAlpha = 0.5;
blurColor = 0x888888;
buttonbarHeight = 30;
buttonbarPadding = new TextPadding(0, 5, 5, 5);
buttonInterval = 5;
}

}

}

Go to AdvAlertWindow.as. Declare this variable here too:

private var buttonInterval:Number;

Update the setSkin() function so that it applies the value from skin object to buttonInterval:

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

Go to the constructor function now, and add a for..loop that adds all the buttons to the container:

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

setSkin(sk);

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

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

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

updateDraw();
}

We now have the buttons on stage, all that's left to do is position them!

Add a new loop in the updateDraw() function that positions the buttons based on the provided data:

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

Full AdvAlertWindow.as code:

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

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

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

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

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

setSkin(sk);

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

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

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

updateDraw();
}

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

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

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

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

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

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

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

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

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

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

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

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


}

}

Now you can add placeholder buttons to alert windows from main.as:

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

We'll continue improving the buttons next time.

Thanks for reading!

No comments:

Post a Comment