Get Adobe Flash player

My Flash ToolBox

My AS3 development environment of choice is FlashDevelop. When I moved from the Flash IDE the first thing I missed were the built-in components. You can wrap them up in a .swc file and bring them with you, but I often found that custom skins or behaviors would be missing, and I had no means of fixing that. When I had successfully imported custom skins, and I wanted to customize them further midway through a project, I had to go back to the Flash IDE, make the adjustments, save the .swc and, hopefully, bring it back complete into FlashDevelop. It was not long before I got around to making own components, and once I did, I realized the freedom in being able to make them look, feel and work the way I, and my clients, wanted them to.

My objective was to make tools that were easy to skin and easy to customize. Since all the tools presented here use the AS3 Drawing API, skinning them is a matter of deciding what color something will be, or what size you need it. Customizing them to perform the way you want is a matter of knowing how they work and adding in the new feature. What I want to do in this article is introduce you to the tools, show you how to use them, skin them, and describe the built-in options. Included in the toolbox is the Button, Check Box, Radio Button, Slider, Color Picker, Icon Button, ComboBox, and Calendar.

You can download a zip file called AS3Toolbox.zip that contains all the files needed to use the above components, and the FlashDevelop project ToolBoxDemo which is shown below.

The ToolBox Demo Movie

The movie below demonstrates each of the components and, where applicable, shows you a skinned version.

The Button

The button is fairly straightforward to set up and use. A basic example looks like this:

btn = new BtnTB();
btn.x btn.x = xPos;
btn.y = yPos;
btn.setSize(100, 20);
btn.btnTxt = "My Button";
btn.turnOff = true;
btn.offTime = 5000;
btn.addEventListener(BtnTB.BTN_CLICK, didClick);
addChild(btn);

private function btnClickHandler(e:Event):void {
    trace("Clicked button");
}

One of the features that I wanted my button to have was a built-in turn off. I found that people often tend to double click buttons and this screws up certain situations, such as logging into an application. Here you see two variables - turnOff and offTime. Setting turnOff to true will turn the button off after the first click and keep it off for the time specified in the offTime variable. No more double click mistakes. Now lets look at a skinned button.

btnSkinned = new BtnTB();
btnSkinned.x = xPos;
btnSkinned.y = yPos;
btnSkinned.setSize(100, 20);
btnSkinned.upColors = [0x0156af, 0x004083];
btnSkinned.overColors = [0x036cda, 0x004083];
btnSkinned.strokeColor = 0x0090ff;
btnSkinned.strokeColorOver = 0x00ccff;
btnSkinned.btnTxtColor = 0xffffff;
btnSkinned.useFilter = true;
btnSkinned.btnTxt = "Skinned Button";
btnSkinned.turnOff = true;
btnSkinned.offTime = 5000;
btnSkinned.addEventListener(BtnTB.BTN_CLICK, didClick);
btnSkinned.addEventListener(MouseEvent.MOUSE_OVER, btnOverHandler);
btnSkinned.addEventListener(MouseEvent.MOUSE_OUT, btnOutHandler);
addChild(btnSkinned);

private function btnOverHandler(e:MouseEvent):void {
    if(!ibOn){
        ib = new InfoBubbleTB(0xffffff, 0xff0000, 130, "Click to have fun!", "center", 10, 1, 1500);
        if(ib.width > btnSkinned.width){
            ib.x = btnSkinned.x - ((ib.width - btnSkinned.width) / 2);
        }else if(ib.width < btnSkinned.width){
            ib.x = btnSkinned.x + ((btnSkinned.width - ib.width) / 2);
        }else{
            ib.x = btnSkinned.x;
        }
        ib.y = btnSkinned.y - (ib.height + 5);
        addChild(ib);
        ibOn = true;
    }
}

private function btnOutHandler(e:MouseEvent):void {
    if(ibOn){
        removeChild(ib);
        ibOn = false;
    }
}

Here we set the upColors as an array of shades of blue. The button uses a gradient to give it some 3 dimensional qualities. You don't need to set the buttons down colors because it takes the upColors array and reverses it to use as the down colors. This gives us a nice "button pushed" effect. The overColors are usually a lighter color of the first color in the upColors gradient to give you a highlighting effect. Then we set the strokeColor and the strokeColorOver for when the button is moused over. Next we set the btnTxtColor to white so that the button label stands out. I also applied the useFilter flag, and this gives the text a drop shadow which makes the white text a little crisper. There are other public variables you can set for the button to alter its appearance. Have a look in the BtnTB class at the public variables. There are notes beside these explaining what they do.

There is just the one built-in event - BTN_CLICK. Use this event, especially when using the turnOff feature, as it monitors the state of the button and responds appropriately. You can always use other standard events here as well. For instance you could use the MOUSE_OVER and MOUSE_OUT events if you want to show a label explaining the button. The InfoBubbleTB class used here is included in the zip file.

The button has two public functions you can use. The first one enableButton() turns the button on or off by passing in a boolean. The second updateBtnTxt() lets you change the label. This can come in handy if you are using a single button for two or more purposes. For instance, in a content management system a single button could be used to Add New Person, or Edit Existing Person depending on whether a user entered a name or picked an existing one from a drop down menu. You simply pass in the string of what the label will be - myBtn.updateBtnTxt("Add New Person").

The Check Box

The CheckBoxTB class is a very simple class to use. The default example looks like this:

cb = new CheckBoxTB();
cb.x = xPos;
cb.y = yPos + 3;
cb.labelTxt = "Check Me!";
cb.data = 1;
cb.addEventListener(CheckBoxTB.HAS_CHANGED, cbHandler);
addChild(cb);

private function cbHandler(e:Event):void {
	var whichCB:int = e.currentTarget.data;
	trace("Which CB Selected: " + whichCB);
	if(e.currentTarget.cbSelected){
		trace("CB 1 Selected");
	}else{
		trace("CB 1 Not Selected");
	}
}

Depending on how you want to monitor your check boxes you can set the event listener function to work in several ways. You can set a boolean flag and monitor that through the cbSelected property. If you had a lot of check boxes and you wanted to keep them in an array you could use the data property to monitor which ones were selected.

Skinning the checkbox is very easy, as you can see in the example below. You can change the background color of the square, the check mark color, the stroke color, and the text color, which could be handy if you had a dark background. There are a few other properties you can set, and they are explained the CheckBoxTB.as file.

cb2 = new CheckBoxTB();
cb2.x = xPos;
cb2.y = yPos + 3;
cb2.bgColor = 0x000000;
cb2.checkMarkColor = 0xffffff;
cb2.strokeColor = 0xcccccc;
cb2.txtColor = 0xff0000;
cb2.labelTxt = "No Check Me!";
cb2.data = 2;
cb2.addEventListener(CheckBoxTB.HAS_CHANGED, cb2Handler);
addChild(cb2);

There is one public function - updateCB() which you probably won't use often, but it can come in handy if say choosing one thing causes a second thing to be chosen as well. You pass in a boolean value which updates the property cbSelected and either turns the check mark on or off.

The Radio Button Group

Radio Buttons are always in a group, otherwise you would use a check box, right? So I set this up to combine the the radio button group and the radio buttons in order to make it easy to set up and monitor. You need to provide an array which must contain the properties Label and Selected. It can contain whatever else you want, but it must have those two for sure. Next you decide whether you want your buttons set out horizontally or vertically. You can use the the event listener function to monitor which radio button is selected and use that result as an index against your rbgArray.

Skinning the radio button group is very similar to the check boxes, and all the details are outlined in the RadioButtonGroupTB.as class.

private var rbgArray:Array = [{Label:"Button 1", Selected:false}, {Label:"Long Name Button 2", Selected:true}, {Label:"Button 3", Selected:false}];

rbg = new RadioBtnGroupTB();
rbg.x = xPos;
rbg.y = yPos;
rbg.btns = rbgArray;
rbg.layout = "horz";
rbg.addEventListener(RadioBtnGroupTB.SELECTED_RADIO, getSelectedRB);
addChild(rbg);

private function getSelectedRB(e:Event):void {
	var selectedRB:int = rbg.selected;
	trace("selectedRB: " + selectedRB);
}

The Slider

There is a full tutorial on building the slider available here: Slider Tutorial.

The example usage shown here is very basic and uses a simple 0 - 100 scale, which is probably the most common, but you have a number of options when setting your slider up.

xs = new SliderTB();
xs.x = xPos;
xs.y = yPos;
xs.useSliderBubble = true;
xs.addEventListener(SliderTB.SLIDER_READY, xsHandler);
addChild(xs);

private function xsHandler(e:Event):void {
	var sliderPassNum:Number = xs.passNum;
	trace("Slider Pass Num: " + sliderPassNum);
}

You could pass in a custom scale to be used in the following format:

private var sArray:Array = [{Txt:"0", data:0}, {Txt:"100", data:100}, {Txt:"1K", data:1000}, {Txt:"10K", data:10000}, {Txt:"100K", data:100000}, {Txt:"1M", data:1000000}];

You can set the bubble to show or not. The default is false. You can set the flag constantUpdate to either get the slider position on a continuous basis or just when the triangle icon has stopped moving. This is a handy property if you are using the slider for scaling.

You can easily skin the slider and change the track color, icon color, text color and set various dimensions. These options are all explained in the SliderTB.as class.

The slider has one public function - resetSlider() which lets you reset the triangle icon to whatever the value of the property startNum is.

The Color Picker

This component provides a way for your users to select a color and pass it into your main program.

cp = new ColorPickerTB();
cp.x = xPos;
cp.y = yPos;
cp.cpPos = "right";
cp.colorPallette = ["0xff0000", "0x00ff00", "0xfff600", "0xffba00"];
cp.iconUpColors = [0x0265cc, 0x004083];
cp.iconOverColors = [0x499ff9, 0x004083];
cp.addEventListener(ColorPickerTB.COLOR_READY, getColor);
cp.addEventListener(MouseEvent.CLICK, cpDepth);
addChild(cp);

private function getColor(e:Event):void {
	//trace("e.currentTarget.buttonSelected: " + e.currentTarget.buttonSelected);
	trace("Chosen color: " + cp.selectedColor);
}

private function cpDepth(e:MouseEvent):void {
	setChildIndex(cp, numChildren - 1);
}

You have several options you can use to customize the color picker. You can set your own color pallette. To do this pass in a array of colors cast as strings. The color picker automatically adjusts its size to suit the number of colors in your pallette.

You can customize the icon button used to open the color picker. These properties are the same as you find in the Button component. You pass in an array for the "up" colors to be used as a gradient. The down colors are calculated by the component and are simply the reverse of the iconUpColors array. The iconOverColors are the highlighted version of the up colors to give you a moused over effect. You can use the iconSquareColors property to tell the icon what colors you want for the little squares. The default array uses five colors, and depending on the overall size of your button, this is probably as many as you want to use because of the circle indicator which sits in the lower right hand corner. This indicator telegraphs the selected color.

Using the cpPos property you can set the position of the pop up color pallette. The available options are "left", "right", "center", "top", and "bottom".

There are two event listeners. The first one signals you that a color has been selected and invites you to come and get it, and the second one is used to manage the depth of the component so that it will be above everything else on screen when it is opened.

The Icon Button

This component is designed to allow you to bring in outside artwork and use it as a button. For the Calendar and the Color Picker components I was able to create a decent icon with just the drawing API, but there are some cases where it is simply more practical to import artwork from PhotoShop or similar programs. I designed this tool for use with FlashDevelop and the embed methods shown here work with that, so for use with other IDE's you will need to adapt the embed methods to suit. The set up is simple - you pass the class four bitmaps which represent the buttons up, over, down and off states. The event listener function simply responds the MouseEvent.CLICK event.

cBtn = new IconButtonTB();
cBtn.x = xPos;
cBtn.y = yPos;
cBtn.upBM = clrUp;
cBtn.overBM = clrOver;
cBtn.downBM = clrDown;
cBtn.offBM = clrOff;
cBtn.buttonMode = true;
cBtn.mouseChildren = false;
cBtn.addEventListener(MouseEvent.CLICK, iconHandler);
addChild(cBtn);

private function iconHandler(e:MouseEvent):void {
	trace("Icon clicked");
}

This shows how the images are imported for use within the FlashDevelop environment.

[Embed(source="/../lib/colorIconDown.png")]
private var ColorDown:Class;
private var clrDown:Bitmap = new ColorDown();

[Embed(source="/../lib/colorIconUp.png")]
private var ColorUp:Class;
private var clrUp:Bitmap = new ColorUp();

[Embed(source="/../lib/colorIconOver.png")]
private var ColorOver:Class;
private var clrOver:Bitmap = new ColorOver();

[Embed(source="/../lib/colorIconDisabled.png")]
private var ColorOff:Class;
private var clrOff:Bitmap = new ColorOff();

The ComboBox

For me the ComboBox always lacked a few features I wanted it to have, so I have made this version to include multiple selection, an auto-complete search feature, and an auto-width feature for the drop down list. All of the tools we have looked at so far are self contained. The ComboBox combines several tools - the ListTB, the ScrollbarTB, the BtnTB and a couple of special buttons. Aside from the special buttons, these other tools can be used independently. In the demo movie you are shown a single pick and a multi-pick version. Let's start with the single pick.

comboTest = new ComboBoxTB();
comboTest.x = xPos;
comboTest.y = yPos;
comboTest.comboWidth = 120;
comboTest.comboHeight = 20;
comboTest.name = "test";
comboTest.displayArray = comboArray;
comboTest.addEventListener(ComboBoxTB.PASS_CHOICE, comboHandler);
comboTest.addEventListener(MouseEvent.CLICK, setComboDepth);
addChild(comboTest);


private function comboHandler(e:Event):void {
	var ind:int = comboTest.pickedIndex;
}
		
private function setComboDepth(e:MouseEvent):void {
	switch(e.currentTarget.name){
		case "test":
			setChildIndex(comboTest, numChildren - 1);
			break;
		case "testM":
			setChildIndex(comboTestM, numChildren - 1);
			break;
	}
}

If you look in the ComboBoxTB.as file you will see many public variables. There are so many because of the fact that we are combining the the ListTB, the ScrollbarTB and the BtnTB components. The example ComboBoxTB above uses all the defaults, including the multiPick variable whose default is false. The only things we need to provide are the width and the height, the name and the array we want to use.

The array you provide can be contain any number of properties, but has a couple of special requirements. At a minimum it must contain: {label:"Item 1", data:0}. The label property is what will show in the drop down list. The data property can be either a string or an integer, and is used to discover the selected index, so it must be present. And, your array must not contain a property called FirstLetter. This is because the code adds this property to your array itself. It does this because when dealing with very large data sets the processing for the auto-complete feature can become quite slow. In order to overcome this limitation the code grabs the first letter of each label in your array, and puts it in the property FirstLetter which it creates.

We use two event listeners. The first one is particular to the ComboBoxTB component and will enable us to gather the selected index. The second one is a mouse event and will set the proper depth for the component so that the drop down list will be on top of anything that might be under the ComboBoxTB component. The name property we assigned the component tells us which combobox we are dealing with in the cases where you have more than one.

To skin the component you have virtually total control. In the ComboBoxTB.as file you will find the variables broken down into the various components, each with an explanation of what it is used for. You can change the appearance using color - comboColors is an array which determines the gradient color of the combobox body - thumbColor is used to set the scrollbar thumb button and up and down button gradient colors - upColor determines the list item color in the up position. You can set the width and height of the combobox. The thing to note here is that the width you set includes the button with the icon which creates the drop down menu. The default size for this button is 20 pixels, so if you choose a comboWidth of 120, the text area will be 100 wide + 20 for the button. Most of these variables are pretty straight forward. A couple which might not be so obvious include - topLoad, a boolean which determines whether the drop down list is shown below the component (default) or, in the case where your component is placed at the bottom of your movie, you need the list to be displayed above the combobox body. The variable dontUseStage is also a boolean whose default is false. The combobox component has a built in feature to close the drop down list if the stage area around it is clicked. There are times when this is not desired and you can set this variable to true in order to stop that default behavior.

Let's look at the multi-pick version now.

comboTestM = new ComboBoxTB();
comboTestM.x = xPos;
comboTestM.y = yPos;
comboTestM.comboWidth = 120;
comboTestM.comboHeight = 20;
comboTestM.name = "testM";
comboTestM.multiPick = true;
comboTestM.displayArray = comboArray;
comboTestM.addEventListener(ComboBoxTB.PASS_MULTI_CHOICE, comboMultiHandler);
comboTestM.addEventListener(MouseEvent.CLICK, setComboDepth);
addChild(comboTestM);
			
private function comboMultiHandler(e:Event):void {
	var pa:Array = comboTestM.pickedArray;
	trace("pa.length: " + pa.length);
}		

The two differences in the multi-pick version of the combobox are the variable multiPick being set to true and choice of event listener.

The problem with having a multi-pick combobox component is that you need to provide the user a way to say "I'm done". In a single pick combobox this is accomplished by simply selecting the item on the list you want and the rest is assumed. In order to over come that limitation, when you set the variable multiPick to true it tells the ComboBoxTB file to add a few extra buttons. The "A" button lets you select all, the "C" button clears all your choices and the "G" button says "Go - I'm done!" and sends the event to your main script. There are cases where having the "A" button available is not desirable - for instance you must only pick 2 of the choices presented - so that button has a boolean variable called useAllBtn, which you can set to false to suppress it. These additional buttons are added to the overall width of your combobox, so if you set comboWidth at 100, you must add an additional 20 pixels of width for each button.

Being a multi-pick component means that the information sent back is also slightly different from the single pick version. Instead of sending back an index, the component now sends you back an array of the objects you selected. This is why you have a different event handler. The way the multi-pick version works is also slightly different. Instead of showing the choice you made in the components' text field, it shows you the number of choices you have made. The selections are highlighted in the list as well so you can review them, and will remain highlighted until you use the C for clear button, or click on the selected item a second time, which will clear it as one of your selections. This way you can go back at anytime and add additional items to your selected array.

There are two additional events that belong to this component and they are "CLEAR_COMBO" and "UNDO_MULTI_CHOICE". I don't use them very often, but depending on your situation it can be handy to know when the choices are cleared within the combobox and when individual choices are de-selected.

There are some public functions within the ComboBoxTB.as class and we'll take a look at those next. The first one of these is updateInfo(). You use this to pass in a new array. There are a few different scenarios where I use this. One example would be where you are removing a chosen item from an array and want to renew the combobox to reflect this. In this case you simply pass in the updated array. Another case would involve starting with an empty combobox instance. A scenario for this would be where a user needs to pick something from combobox #1 ( such as a client name ) before the data ( the clients favorite colors ) is ready to fill combobox #2. In this sort of a case you can set the property promptTxt of the empty combobox to an empty string when you create the instance, like this:

myEmptyCombo.promptTxt = "";

The empty string tells the class to build the combobox with the "off" setting in effect. When you want to then fill the combobox you need to use the public function updatePrompt() in order to set your prompt text to something other than any empty string, then use the public function updateComboOff() to set up the environment, and then pass in the array using the updateInfo() function. All of that would look like this:

myEmptyCombo.updatePrompt("Select or Type");
myEmptyCombo.updateComboOff("on");
myEmptyCombo.updateInfo(myArray);

The last public function setSelected() lets you either set the selected index or de-select an already selected item. To set the selection, pass in the index number - myCombo.setSelected(5). To de-select a previous selection pass in -2, like this: myCombo.setSelected(-2)

The Calendar

This component lets a user pick dates from a calendar to use within the main program. This calendar has the ability to set a date range so that if you want users to only be able to select dates within a particular time frame you can easily do that. The demonstration shows you a start and end calendar that lets you pick between April 15, 2012 to April 23, 2014. Here is the code to set up these two instances:

//CALENDAR VARIABLES
private var xCalStart:CalendarTB;
private var xCalEnd:CalendarTB;

private var startDay:int = 15;
private var startMonth:int = 3; //NOTE: Months work on a 0 - 11 system
private var startYear:int = 2012;
private var endDay:int = 23;
private var endMonth:int = 3;//NOTE: Months work on a 0 - 11 system
private var endYear:int = 2014;

xCalStart = new CalendarTB(false, startMonth, startYear);
xCalStart.x = xPos;
xCalStart.y = yPos;
xCalStart.name = "startCal";
xCalStart.stopDateEnd = endDay;
xCalStart.stopMonthEnd = endMonth;
xCalStart.stopDateStart = startDay;
xCalStart.stopMonthStart = startMonth;
xCalStart.startYear = startYear;
xCalStart.stopYear = endYear;
xCalStart.addEventListener(CalendarTB.DP_READY, doStartDate);
xCalStart.addEventListener(MouseEvent.CLICK, setComboDepth);
addChild(xCalStart);
			
xCalEnd = new CalendarTB(false, endMonth, endYear);
xCalEnd.x = xPos;
xCalEnd.y = yPos;
xCalEnd.name = "endCal";
xCalEnd.stopDateEnd = endDay;
xCalEnd.stopMonthEnd = endMonth;
xCalEnd.stopDateStart = startDay;
xCalEnd.stopMonthStart = startMonth;
xCalEnd.startYear = startYear;
xCalEnd.stopYear = endYear;
xCalEnd.addEventListener(CalendarTB.DP_READY, doEndDate);
xCalEnd.addEventListener(MouseEvent.CLICK, setComboDepth);
addChild(xCalEnd);

private function doStartDate(e:Event):void {
	var sd:String = formatDate(xCalStart.datePicked);
	trace("Start Date: " + sd);
	var sdf:String = formatDateDisplay(xCalStart.datePicked);
	trace("Start Date Display: " + sdf);
	startTxt.text = sd;
}

private function doEndDate(e:Event):void {
	var ed:String = formatDate(xCalEnd.datePicked);
	trace("End Date: " + ed);
	var edf:String = formatDateDisplay(xCalEnd.datePicked);
	trace("End Date Display: " + edf);
	endTxt.text = ed;
}

private function formatDate(newDate:Number):String{
	var myDate:Date = new Date(newDate);
	var m:int = myDate.getMonth();
	m = m + 1;
	var ms:String = String(m);
	if(ms.length == 1){
		ms = "0" + ms;
	}
	var d:int = myDate.getDate();
	var ds:String = String(d);
	if(ds.length == 1){
		ds = "0" + ds;
	}
	var dateString:String = myDate.getFullYear() + "-" + ms + "-" + ds;
	return dateString;
}

private function formatDateDisplay(newDate:Number):String{
	var myDate:Date = new Date(newDate);
	var months:Array = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
	var dateString:String = months[myDate.getMonth()] + " " + myDate.getDate() + ", " + myDate.getFullYear();
	return dateString;
}

private function setComboDepth(e:MouseEvent):void {
	switch(e.currentTarget.name){
		case "startCal":
			setChildIndex(xCalStart, numChildren - 1);
			break;
		case "endCal":
			setChildIndex(xCalEnd, numChildren - 1);
			break;
	}
}

First of all we see the variables. These represent the start date and end of your date range. These are optional, and, if you do not set them, then the calendar range is unlimited. You can also set just the start or just the end in order to limit the range on one side or the other. The variables are pretty straight forward with the exception of the startMonth and stopMonth, which you must keep in mind work like an array, that is with the first number being 0. If you are using a date range, you can pass that info into the calendar instance when you create it if you want the instance to start with that month and year. In the new CalendarTB constructor there are three variables ( all optional ) which you can pass. The first one is a boolean which tells the calendar whether to use hours, minutes and seconds for the date. The default is false. The second one is the month you want the calendar to open with, and the third is the year you want the calendar to open with. The default for these last two is -1 and that will tell the calendar to open with the current month and year.

There are two other variables to set. The first one, calPos determines where the calendar instances pops up in relation to the calendar icon button. The available settings are "right" and "left", with "right" being the default. The second variable to be set is the name property. This is so you can identify it for the set depth function. Here that function is called setComboDepth because in the demonstration this function is used for the comboboxes as well. This function insures that the calendar instance you create when you click the calendar icon button will be on top of whatever else is on screen.

The only event native to the calendar itself is the DP_READY, which fires once the user has clicked on a date to select it. The calendar instance returns a number and the two additional functions provided can be used to format that number. The formatDate() function returns a date like this: 2012-04-16 and the formatDateDisplay() function returns a date like this: Apr 16, 2012.

This is the one component of mine that I haven't put the time into to make it skinnable. You could certainly add in variables to hold the color and size values of the various components, but there are a lot of inter-dependancies with the sizing that will make it somewhat problematic. So far all the places I have used the calendar in the client has been happy with the default color and size. Sooner or later I will no doubt run into someone who will want something different and at that point I will add in the ability to change it.

The calendar has two public functions which, admittedly, I seldom ever use, but they are there just in case. The first one - removeCal() does exactly that. Normally the calendar's visible property is set to false within the CalendarTB class, but should a situation arise where you need to do it from outside the class you would just call this function. The public function - updateDates(StopDateStart:int, StopMonthStart:int, StartYear:int, StopDateEnd:int, StopMonthEnd:int, StopYear:int, CurMonth:int, CurYear:int) - lets you change the calendars date range on the fly. For properties you don't want to set just pass in -1.

Customize Your Components

Customization is a bit beyond the scope of what I set out to do here, but it is one of the big advantages of using your own components. There a couple of ground rules I follow, so I thought I would pass them on with a small example here.

Suppose you want to add an optional bevel to your button. The steps are basically these: 1) Set up the public variables you'll need. 2) Set the default value of these variables to match the current condition. For example if some feature can be turned off and on with a boolean, make sure that the default value is false. You do this because instances of this component which existed before you added this feature are not prepared for it, so keeping the status quo won't affect the performance. 3) Make sure you think about the effect this addition might have on any of the components other moving parts. Let's get started.

In the BtnTB class add these public variables:

public var bevel:BevelFilter = new BevelFilter(2, 45, 0xffffff, 1, 0x000000, 1, 2, 2, 1, 1);
public var useBevel:Boolean = false;

In the instance of the xb = new ButtonTB(); add the following lines:

if(useBevel){
	xb.filters = [bevel];
}

Then, when you want to use this feature just do this:

btnSkinned.useBevel = true;
btnSkinned.bevel = new BevelFilter(2, 45, 0x00c0ff, 1, 0x004083, 1, 2, 2, 1, 1);

Now you have a new feature, and, if you've done it right, you won't break anything existing. In the case of our new bevel feature we give the bevel variable a default setting and we set the flag useBevel to false. With that set to false, no other existing instances of our BtnTB class will be affected. You will have to go back and manually add the bevel option in the places you want it to be, but you won't have to go to all the places where you don't want it to show up, add the useBevel property and set it to false.

Next on the Agenda

These tools are yours to use as you please. Change them to suit your needs, combine them to make new components, and fix whatever bugs I haven't found yet! These tools are definitely a work in progress, so if you find something not working right and can't figure it out, let me know and I'll see what I can do.

I have several more components which I intend to add to this tool box collection once I have a chance to clean them up a bit. It took me a while to get this many of the tools ready to go as I keep changing and adding features, but then that is the whole point! Stay tuned and I'll let you know when more tools are available. As always, if you have any questions feel free to ask!