Saturday, September 22, 2012

Creating Advanced Alert Window class: Part 20

In this tutorial we'll add the ability to set custom default button skins.

The default button skin value will be passed to the AdvAlertManager object, along with the default alert skin value. Add another parameter to the AdvAlertManager's constructor - buttonSkin. Declare a new variable in the beginning of the class - bSkin - and apply buttonSkin's value to bSkin. If null, set to a new AdvAlertButtonSkin:

private var bSkin:AdvAlertButtonSkin;

/**
 * AdvAlertManager constructor.
 * @paramdefaultWindowContainer Parent container of alert windows.
 * @paramparentWidth Container's width.
 * @paramparentHeight Container's height.
 * @paramwindowSkin Default skin for alert windows.
 * @parambuttonSkin Default skin for buttons in this window.
 */

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

Create a new public function setButtonSkin() which will let the developer change the button skin later:

/**
 * Set skin of all buttons of future created alert windows.
 * @parambuttonSkin Reference to an AdvAlertButtonSkin object.
 */

public function setButtonSkin(buttonSkin:AdvAlertButtonSkin):void {
bSkin = buttonSkin;
}

In the alert() function, we will pass the bSkin value as the last parameter of the new AdvAlertWindow object:

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, bSkin);
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;
private var bSkin:AdvAlertButtonSkin;

/**
 * AdvAlertManager constructor.
 * @paramdefaultWindowContainer Parent container of alert windows.
 * @paramparentWidth Container's width.
 * @paramparentHeight Container's height.
 * @paramwindowSkin Default skin for alert windows.
 * @parambuttonSkin Default skin for buttons in this window.
 */

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

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

/**
 * 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, bSkin);
var b:AdvAlertBlur = new AdvAlertBlur(pWidth, pHeight, skin);
windows.push( { window:w, blur:b } );
defaultContainer.addChild(b);
defaultContainer.addChild(w);

trace("Message: " + text);
}

}

}

In AdvAlertWindow class, receive the defaultButtonSkin value in the constructor and then apply it as the skin of each button in this window. We do this in the loop in the constructor itself, check if the skin of the button is null and then apply the new skin. We can check AdvAlertButton's currentSkin property (which we will add shortly to that class) and compare it to null, before calling setSkin() and updateDraw() functions of the button to apply the skin.

public function AdvAlertWindow(pt:String, ptt:String, pw:int, ph:int, ppos:Point, sk:AdvAlertSkin, bt:Array, defaultButtonSkin:AdvAlertButtonSkin) 
{
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++) {
if (buttons[i].currentSkin == null) {
buttons[i].setSkin(defaultButtonSkin);
buttons[i].updateDraw();
}
addChild(buttons[i]);
}

updateDraw();
}

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;
private var defaultButtonSkin:AdvAlertButtonSkin;

public function AdvAlertWindow(pt:String, ptt:String, pw:int, ph:int, ppos:Point, sk:AdvAlertSkin, bt:Array, defaultButtonSkin:AdvAlertButtonSkin) 
{
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++) {
if (buttons[i].currentSkin == null) {
buttons[i].setSkin(defaultButtonSkin);
buttons[i].updateDraw();
}
addChild(buttons[i]);
}

updateDraw();
}

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

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

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

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

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

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

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

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

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

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

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

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


}

}

Go to AdvAlertButton class and declare a new public variable currentSkin.

Apply the current skin value to this variable in setSkin() function:

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

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

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

private var textField:TextField;
private var txt;

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

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

setSkin(skin);

updateDraw();
}

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

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

//filters
this.filters = filt;

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

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

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

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


}

}

And we're done!

Now, if no default or manual skins are applied to the buttons, the default blue buttons will be displayed. If the developer specifies a button skin in AdvAlertManager object, all buttons will now have that skin by default. And, if the developer sets a custom skin to a specific button using AdvAlertButton constructor, that value will overwrite any default values.

In the main.as code example below, we create a new alert window and set default skin for the buttons to red button skin. Then we manually apply green button skin to the second button, and in the end with have an alert window with 2 red and 1 green buttons:

var redSkin = new AdvAlertButtonSkin();
redSkin.bgRect = new SolidColorRect(0xff4444, [3, 3, 3, 3]);
redSkin.bgStroke = new SolidColorStroke(2, 0x993333);

var greenSkin = new AdvAlertButtonSkin();
greenSkin.bgRect = new SolidColorRect(0x44ff44, [3, 3, 3, 3]);
greenSkin.bgStroke = new SolidColorStroke(2, 0x339933);

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

Thanks for reading!

No comments:

Post a Comment