Posts Tagged ‘GUI’

AS3 Window Class (real-time skinnable)

Wednesday, December 12th, 2007

[edit august 21st 2008] Hey guys this code is available but it is messy and the project has been scrapped. I will pick it up again, probably with OpenGL and C++[/edit]

In an effort to (maybe) find a new job, depending on what happens with my current one, I’m releasing a preview of my GUI classes. This class is a window class. It contains your display objects in a nice, draggable, scrollable and real-time skinnable window. You can make your own graphics for the window and configure button placement, scrollbar offsets, label, offsets and all other text goodies from an external config.xml script. There’s nothing to keep in your library and it’s not that big. It would be nice if anyone who uses it can tell me their memory stats, as I’m currently looking to make sure my code is clean and there are no leaks. Click the link below for a little demo.

Here’s the demo!

If you’re interested in using the class you can dive in headfirst at your own risk. It’s kinda long (about 1200 lines). I’ll be working on completely revising it from the ground up as it really is a big mess right now.

Source: GUI – mess

Developing a Pure AS3 GUI – Part One (Scaling Bars)

Monday, November 19th, 2007

This class has been deprecated and phased out as of 12.7.2007

Writing your own GUI can be a daunting task, most people might find it easier to learn MXML and use Flex Builder or Flash Components than to waste their time writing GUI code and Photoshopping images. I on the other hand hate proprietary frameworks [like MXML] and really like the clean approach of creating classes of GUI elements that build on each other to make an interface. This post is the first in a series of posts designed to step through MY method of GUI design.

Example
Source

I start the process at windows. Windows hold all the content of a graphical operating system, the mother of all interfaces, so why not start there? Well, windows are super complicated, so first we’ll start by writing the components of a window. We’ll need a window bar that holds the close, minimize and optimize buttons and scales to a given size. This means we’ll need bars [vertical and horizontal] that tile. Don’t let the name Scaling Bars trick you, these bars aren’t really scaling, they’re tiling the bitmaps given to them in the constructor. Here’s the beginning code where we set up all our variables.

package com.efnx.GUI
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  scalingBar is an object that given three images will scale to a certain size, tiling the middle image //
    //  and placing the end images on either side (overall width will be the given size) //////////////////////
    //////////////////////////////////////////////////////////////////////////////////////
   
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // usage: bar:scalingBar = new scalingBar(new Array("toporleftImage.xxx","middleImage.xxx","bottomorrightImage.xxx"), [tileDir:String: either "horizontal" or "vertical");  //
    //        addChild(bar);          ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //        bar.resize(someSize);  //
    //////////////////////////////////
   
    import com.efnx.utils.loadedSprite;
    import com.efnx.utils.aquireResources;
   
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import flash.display.Sprite;
    import flash.geom.Rectangle;
    import flash.geom.Point;
   
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class scalingBar extends Sprite
    {
        private var tileDirection:String;
        private var tileSize:int;
        private var minimumSize:int;
        private var side1:loadedSprite;
        private var middle:loadedSprite;
        private var side2:loadedSprite;
        private var loaded:int = 0;
        private var testing:Boolean;
       
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Okay. We’ve imported some classes that I’ve written myself that I haven’t talked about before, don’t worry, I’ve included them in the source and will post about them later. The vars are all pretty self-explanatory. The loadedSprites are a class of Sprite I’ve developed to make importing graphics a little easier on me. Given a path to an image it simply retrieves the image and sticks it inside a Sprite [itself]. On to the constructor:

public function scalingBar(imagePathArray:Array, tileDir:String = "horizontal", _testing:Boolean = false):void
        {
            testing = _testing;
            tileDirection = tileDir;
           
            if(tileDirection != "horizontal" && tileDirection != "vertical")
            {
                throw new Error("scalingBar::init: invalid tiling direction, scalingBar only accepts either \"horizontal\" or \"vertical\".");
                return;
            }
           
            side1 = new loadedSprite(imagePathArray[0], loadCycleComplete, testing); //remove testing parameter
            middle = new loadedSprite(imagePathArray[1], loadCycleComplete, testing); //to keep from tracing
            side2 = new loadedSprite(imagePathArray[2], loadCycleComplete, testing); //verbose info
           
            side1.name = imagePathArray[0];
            middle.name = imagePathArray[1];
            side2.name = imagePathArray[2];
           
            addChild(side1);
            addChild(middle);
            addChild(side2);
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

When instantiating the scalingBar class, create an array consisting of paths to the three images to be used for the bar, the left [or top], the middle, and the right [or bottom]. If left to the defaults your bar will tile and size horizontally. You can pass “vertical” as the second parameter to set the bar up to tile horizontally. Next we have the functions that take care of placement and size checks after the images are loaded. loadedSprite operates whatever function was passed to it as the second parameter in its instantiation, so no external event listeners are needed. We passed loadCycleComplete to the loadedSprites so that function will be called each time one is done loading:

        private function loadCycleComplete():void
        {
            loaded++;
            if(testing)trace("scalingBar::loadCycleComplete: has loaded " + loaded + "/3 resources. ");
            if(loaded == 3)
            {  
                if(tileDirection == "horizontal")
                {
                    tileSize = middle.width;
                }else
                {
                    tileSize = middle.height;
                }
                if(testing)trace("scalingBar::loadCycleComplete: finished loading.");
                placeParts();
                updateSize();
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        private function updateSize():void
        {
            if(tileDirection == "horizontal")
            {
                minimumSize = side1.width + side2.width + tileSize;
                if(testing)trace("scalingBar::updateSize: side1.width, side2.width, tileSize:" + side1.width, side2.width, tileSize);
            }else
            {
                minimumSize = side1.height + side2.height+ tileSize;
                if(testing)trace("scalingBar::updateSize: side1.height, side2.height, tileSize:" + side1.height, side2.height, tileSize);
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        private function placeParts():void
        {
            if(tileDirection == "horizontal")
            {
                middle.x = side1.width;
                side2.x = middle.x + middle.width;
            }else
            {
                middle.y = side1.height;
                side2.y = middle.y + middle.height;
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Almost done! The last part is the resize function, which takes an integer size and scales the entire bar either horizontally or vertically, depending on what you have specified. This is the real meat of the class. The resize function moves the bottom [or left] image to the border of the given size, then tiles the middle image over however many times needed until it reaches the bottom [or left] image:

public function resize(size:int):void
        {
           
            if(size >= minimumSize)
            {
                if(testing)trace("scalingBar::resize: valid resize value.");
                var bmd:BitmapData = middle.bitmapData.clone();
                var i:int = 0;
           
                if(tileDirection == "horizontal")
                {
                    side2.x = size - side2.width;
                    if(testing)trace("scalingBar::resize(): side1,side2 width and minimumSize:" + side1.width, side2.height, minimumSize);
                    middle.bitmap.bitmapData = new BitmapData(size - side1.width - side2.width, bmd.height, true, 0x00000000);
                    if(testing)trace("window::resize(): windowbarmiddle.bitmap.bitmapData: " + middle.bitmap.bitmapData.width, middle.bitmap.bitmapData.height);
                   
                    for(i = 0; i*bmd.width<middle.bitmap.bitmapData.width; i++)
                    {
                        middle.bitmap.bitmapData.copyPixels(bmd, new Rectangle(0, 0, bmd.width, bmd.height), new Point(i*bmd.width, 0));
                        if(testing)trace("window::resize(): copying pixels to middle.x=" + i*bmd.width);
                    }
                }else if(tileDirection == "vertical")
                {
                    side2.y = size - side2.height;
                    if(testing)trace("scalingBar::resize(): bmd dimensions:" + bmd.width, bmd.height);
                    middle.bitmap.bitmapData = new BitmapData(bmd.width, size - side1.height - side2.height, true, 0x00000000);
                    if(testing)trace("window::resize(): windowbarmiddle.bitmap.bitmapData w,h: " + middle.bitmap.bitmapData.width, middle.bitmap.bitmapData.height);
                   
                    for(i = 0; i*bmd.height<middle.bitmap.bitmapData.height; i++)
                    {
                        middle.bitmap.bitmapData.copyPixels(bmd, new Rectangle(0, 0, bmd.width, bmd.height), new Point(0, i*bmd.height));
                        if(testing)trace("window::resize(): copying pixels to middle.y = " + i*bmd.height);
                    }
                }
            }else
            {
                if(testing)trace("scalingBar::resize: invalid resize value of " + size + ", resizing at " + minimumSize);
                resize(minimumSize);
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }//end class
}//end package

Example
And there we go! Here is an example of the implementation:

Source
scalingBar source


Follow me on GitHub
Follow me on Google+
Follow me on Twitter