Introduction

Flash is a lightweight cross-platform runtime for rich media, enterprise applications and mobile applications, as well as an integrated development environment. Flash can be programmed in ActionScript 1/2/3.

Wednesday, July 23rd, 2003 at 4:24 pm

Windows Style Menu

Requirements:

1. two layers (one layer with the workarounds and the other with the menu code)
2. three empty movieclips with the linkage names: subButtonSymbol, mainButtonSymbol and popUpMenuSymbol
3. one xml-file named xmlMenuTree
that’s it. Click on read more to see the code.
btw: by now it’s just a beta version. If you recognize any mistakes or things that could be improved I would be thankful if you’d write me a mail.

download fla
download xml
show example

Workarounds:

// :: GET_NEXT_DEPTH :: //
MovieClip.prototype.getNextDepth = function(){
        var t = -Infinity;
        for(var i in this){
                if(this[i].getDepth() != null && this[i]._parent == this){
                        t = Math.max(t, this[i].getDepth());
                }
        }
        return (t > -1) ? ++t: 0;
}

// :: GET_TEXT_EXTENT :: //
_global.TextFormat2 = TextFormat;
TextFormat = function(){
        super();
        delete this.getTextExtent;
}
TextFormat.prototype = new TextFormat2();
TextFormat.prototype.getTextExtent2 = TextFormat.prototype.getTextExtent;
TextFormat.prototype.getTextExtent = function ( the_str ) {

        // create temporary textfield
        _root.createTextField(”getTextExtentTemp_txt“, 1000000, 1, 1, 10, 10);
        // local reference to text field
        var temp_txt = _root [ “getTextExtentTemp_txt” ];
        // set the text format
        temp_txt.setNewTextFormat( this );
        // populate textfield with string
        temp_txt.text = the_str;
        // get dimensions
        var w = temp_txt.textWidth;
        var h = temp_txt.textHeight;
        // wrap in object
        var textExtent = { width: w, height: h };

        // remove the textfield
        temp_txt.removeTextField();

        // return dimensions object
        return textExtent;
}
ASSetPropFlags(_global,”TextFormat,TextFormat2“,131);

// :: CREATE_TEXT_FIELD :: //
MovieClip.prototype.createTextField2 = MovieClip.prototype.createTextField;
MovieClip.prototype.createTextField = function(name, depth, x, y, w, h){
        this.createTextField2(name, depth, x, y, w, h);
        return this[name];
}

Code:

MovieClip.prototype.useHandCursor = false;

// :: POP_UP_MENU_CLASS :: //
PopUpMenuClass = function(){
        this._x = 0;
        this._y = 0;
        this.width = Stage.width;
        this.height = 20;
        this.xmlFile = “xmlMenuTree.xml“;
        this.init();
}
PopUpMenuClass.prototype = new MovieClip();
PopUpMenuClass.prototype.init = function(){
        this.loadXMLFile();
        this.drawBackground();
}
PopUpMenuClass.prototype.loadXMLFile = function(){
        var xml = new XML();
        xml.master = this;
        xml.ignoreWhite = true;
        xml.onLoad = function(success){
                if(success){
                        this.master.menuTree_arr = this.master.handleXMLData(this.firstChild.childNodes);
                        this.master.createMainMenu();
                }
        }
        xml.load(this.xmlFile);
}
PopUpMenuClass.prototype.handleXMLData = function(child){
        var menuTree_arr = new Array();
        for(var i=0; i < child.length; i++){
                var temp_obj = new Object();
                temp_obj.title = child[i].attributes.title;
                temp_obj.func = child[i].attributes.func;
                temp_obj.link = child[i].attributes.link;
                temp_obj.symbol = child[i].attributes.symbol;
                if(child[i].childNodes.length > 0){
                        temp_obj.subMenu = this.handleXMLData(child[i].childNodes);
                }
                menuTree_arr.push(temp_obj);
        }
        return menuTree_arr;
}
PopUpMenuClass.prototype.drawBackground = function(){
        this.createEmptyMovieClip(”background_mc“, this.getNextDepth());
        with(this.background_mc){
                beginFill(0xD4D0C8, 100);
                lineStyle(1, 0×404040, 100);
                moveTo(0, this.height);
                lineTo(this.width, this.height);
                lineStyle(0, 0×404040, 0);
                lineTo(this.width, 0);
                lineTo(0, 0);
                lineTo(0, this.height);
                endFill();
        }
}
PopUpMenuClass.prototype.createMainMenu = function(){
        for(var i=0; i<this.menuTree_arr.length; i++){
                this.attachMovie(”mainButtonSymbol“, “mainButton“+i, this.getNextDepth());
                this[”mainButton“+i].master = this;
                with(this[”mainButton“+i]){
                        _x = this[”mainButton“+(i-1)]._x+this[”mainButton“+(i-1)]._width+2;
                        _y = 2;
                }
                this[”mainButton“+i].init(this.menuTree_arr[i]);
        }
}
PopUpMenuClass.prototype.createSubMenu = function(x, y, subMenu_arr, target){
        target.createEmptyMovieClip(”subMenu“, target.getNextDepth());
        with(target.subMenu){
                _x = x;
                _y = y;
        }

        var tF = new TextFormat();
        tF.bold = true;
        tF.font = “Tahoma“;
        tF.size = 12;
        for(var i=0; i < subMenu_arr.length; i++){
                var size;
                var textWidth = tF.getTextExtent(subMenu_arr[i].title).width;
                if(textWidth>size){
                        size = textWidth;
                }
        }
        for(var i=0; i < subMenu_arr.length; i++){
                target.subMenu.attachMovie(”subButtonSymbol“, “subButton“+i, target.subMenu.getNextDepth());
                target.subMenu[”subButton“+i].master = [this, target.subMenu];
                target.subMenu[”subButton“+i].width = size;
                with(target.subMenu[”subButton“+i]){
                        _x = 1;
                        _y = target.subMenu[”subButton“+(i-1)]._y+target.subMenu[”subButton“+(i-1)]._height;
                }
                target.subMenu[”subButton“+i].init(subMenu_arr[i]);
        }
        var height = target.subMenu._height-1;
        var width = target.subMenu._width+2;
        with(target.subMenu){
                clear();
                beginFill(0xD4D0C8, 100);
                lineStyle(1, 0xFFFFFF, 100);
                moveTo(width, -1);
                lineTo(0, -1);
                lineTo(0, height);
                lineStyle(1, 0×404040, 100);
                lineTo(width, height);
                lineTo(width, -1);
                endFill();
        }
}
PopUpMenuClass.prototype.removeSubMenu = function(target){
        target.subMenu.removeMovieClip();
        for(var i in target){
                if(typeof target[i] == “movieclip“){
                        target[i].setToDefault();
                }
        }
}
PopUpMenuClass.prototype.onMouseDown = function(){
        if(this.hitTest(_root._xmouse, _root._ymouse, true) == false){
                this.removeSubMenu(this);
        }
}

// :: BUTTON_CLASS :: //
ButtonClass = function(){};
ButtonClass.prototype = new MovieClip();
ButtonClass.prototype.init = function(dataObj){
        this.title = dataObj.title;
        this.func = dataObj.func;
        this.link = dataObj.link;
        this.symbol = dataObj.symbol;
        this.subMenu = dataObj.subMenu;
        this.defineTextFormat();
        this.defineColors();
        this.defineSize();
        this.setSymbol();
        this.draw();
        this.createTitle();
}
ButtonClass.prototype.setSymbol = function(){
        this.attachMovie(this.symbol, “symbol_mc“, this.getNextDepth());
        this.symbol_mc._x = 2;
        this.symbol_mc._y = this.height/2;
        this.width += this.symbol_mc._width+this.symbol_mc._x;
}

// :: MAIN_BUTTON_CLASS :: //
MainButtonClass = function(){};
MainButtonClass.prototype = new ButtonClass();
MainButtonClass.prototype.init = function(dataObj){
        this.type = “main“;
        super.init(dataObj);
}
MainButtonClass.prototype.defineTextFormat = function(){
        this.tF = new TextFormat();
        this.tF.bold = true;
        this.tF.font = “Tahoma“;
        this.tF.size = 12;
}
MainButtonClass.prototype.defineColors = function(){
        this.background_color = 0xD4D0C8;
        this.line1_color = 0xFFFFFF;
        this.line2_color = 0×404040;
}
MainButtonClass.prototype.defineSize = function(){
        this.textSize = this.tF.getTextExtent(this.title);
        this.width = this.textSize.width+4;
        this.height = 16;
}
MainButtonClass.prototype.draw = function(status){
        with(this){
                clear();
                beginFill(this.background_color, 100);
                if(status == “pressed“) lineStyle(1, this.line2_color, 100);
                else if(status == “active“) lineStyle(1, this.line1_color, 100);
                moveTo(this.width, 0);
                lineTo(0, 0);
                lineTo(0, this.height);
                if(status == “pressed“) lineStyle(1, this.line1_color, 100);
                else if(status == “active“) lineStyle(1, this.line2_color, 100);
                lineTo(this.width, this.height);
                lineTo(this.width, 0);
                endFill();
        }
}
MainButtonClass.prototype.createTitle = function(){
        this.createTextField(”title_txt“, this.getNextDepth(), 0, 0, 0, 0);
        this.title_txt._x = this.symbol_mc._x+this.symbol_mc._width;
        this.title_txt._y = (this.height-this.textSize.height)/2-2;
        this.title_txt.autoSize = “left“;
        this.title_txt.selectable = false;
        this.title_txt.htmlText = this.title;
        this.title_txt.setTextFormat(this.tF);
}
MainButtonClass.prototype.openSubMenu = function(){
        this.master.createSubMenu(this._x, this._y+this.height+3, this.subMenu, this.master);
}
MainButtonClass.prototype.closeSubMenu = function(){
        this.master.removeSubMenu(this.master);
}
MainButtonClass.prototype.setToDefault = function(){
        this.draw();
        this.pressed = false;
}
MainButtonClass.prototype.onRollOver = function(){
        if(!this.pressed){
                if(this.master.subMenu != undefined
                && this.subMenu != undefined){
                        this.closeSubMenu();
                        this.openSubMenu();
                        this.draw(”pressed“);
                        this.pressed = !this.pressed;
                } else {
                        this.draw(”active“);
                }
        }
}
MainButtonClass.prototype.onRollOut = function(){
        if(!this.pressed){
                this.draw();
        }
}
MainButtonClass.prototype.onPress = function(){
        if(!this.pressed){
                this.closeSubMenu();
                if(this.subMenu != undefined){
                        this.openSubMenu();
                }
                this.draw(”pressed“);
                this.pressed = !this.pressed;
        } else {
                this.closeSubMenu();
                this.draw();
        }
}

// :: SUB_BUTTON_CLASS :: //
SubButtonClass = function(){};
SubButtonClass.prototype = new ButtonClass();
SubButtonClass.prototype.init = function(dataObj){
        this.type = “sub“;
        super.init(dataObj);
}
SubButtonClass.prototype.defineTextFormat = function(){
        this.tFStatic = new TextFormat();
        this.tFStatic.bold = true;
        this.tFStatic.font = “Tahoma“;
        this.tFStatic.color = 0×000000;
        this.tFStatic.size = 12;

        this.tFActive = new TextFormat();
        this.tFActive.color = 0xFFFFFF;
}
SubButtonClass.prototype.defineColors = function(){
        this.backgroundStatic_color = 0xD4D0C8;
        this.backgroundActive_color = 0×0A246A;
}
SubButtonClass.prototype.defineSize = function(){
        this.textSize = this.tFStatic.getTextExtent(this.title);
        this.width = this.width+20;
        this.height = 16;
}
SubButtonClass.prototype.draw = function(status){
        with(this){
                clear();
                status == “active” ? beginFill(this.backgroundActive_color, 100) : beginFill(this.backgroundStatic_color, 100);
                moveTo(this.width+w, 0);
                lineTo(0, 0);
                lineTo(0, this.height);
                lineTo(this.width+w, this.height);
                lineTo(this.width+w, 0);
                endFill();
        }
        if(this.subMenu != undefined){
                with(this){
                        status == “active” ? beginFill(0xFFFFFF, 100) : beginFill(0×000000, 100);
                        moveTo(this.width-4, this.height/2);
                        lineTo(this.width-10, this.height/2-5);
                        lineTo(this.width-10, this.height/2+5);
                        lineTo(this.width-4, this.height/2);
                }
        }
}
SubButtonClass.prototype.createTitle = function(){
        this.createTextField(”title_txt“, this.getNextDepth(), 0, 0, 0, 0);
        this.title_txt._x = this.symbol_mc._width+this.symbol_mc._x+2;
        this.title_txt._y = (this.height-this.textSize.height)/2-2;
        this.title_txt.autoSize = “left“;
        this.title_txt.selectable = false;
        this.title_txt.htmlText = this.title;
        this.title_txt.setTextFormat(this.tFStatic);
}
SubButtonClass.prototype.openSubMenu = function(){
        this.master[0].createSubMenu(this._x+this.width, this._y, this.subMenu, this.master[1]);
}
SubButtonClass.prototype.closeSubMenu = function(){
        this.master[0].removeSubMenu(this.master[1]);
}
SubButtonClass.prototype.setToDefault = function(){
        this.draw();
        this.pressed = false;
        this.title_txt.setTextFormat(this.tFStatic);
}
SubButtonClass.prototype.onRollOver = function(){
        this.closeSubMenu();
        if(this.subMenu != undefined){
                this.openSubMenu();
        }
        this.draw(”active“);
        this.title_txt.setTextFormat(this.tFActive);
}

// example
Object.registerClass(”popUpMenuSymbol“, popUpMenuClass);
Object.registerClass(”mainButtonSymbol“, mainButtonClass);
Object.registerClass(”subButtonSymbol“, subButtonClass);

this.attachMovie(”popUpMenuSymbol“, “popUpMenuCon_mc“, this.getNextDepth());

5 Responses to “Windows Style Menu”

  1. Mario

    hy simon !

    i have tried your xml-menue, itīs fantastic !!!

    but please, can you tell me how i can set a link in the xml-file.

    such as: http:www.domain.net

    i have tried averything, but it donīt works. :(
    thx for being helpful !!!

    gtx, mario

  2. Simon Wacker

    Hi Mario!
    Sorry for the delay but just recognized your comment. Add the following to the Button-Class:

    ButtonClass.prototype.onRelease = function(){
    if(this.func == “getURL”){
    var linkArray = this.link.split(”,”);
    this.getURL(linkArray[0], linkArray[1]);
    }
    }

    And then copy the following into the xml-file:

    Should work now.

    Simon

  3. Simon Wacker

    Damn. He absorbed the few lines aftern And then copy… .
    So here’s another try. The value of the func var must be getURL and the value of the link var must look like the following: http://www.flashforum.de, _blank.

  4. Jorge Alegre

    I love your menu.. but i get this error in flash MX…


    **Warning** Scene=Szene 1, layer=Script:, frame=1:Line 18: Case-insensitive identifier ‘xml’ will obscure built-in object ‘XML’.
    var xml = new XML();

    Total ActionScript Errors: 1 Reported Errors: 1

    what’s wrong?

    Jorge

  5. Simon Wacker

    Hi Jorge.
    There’s nothing wrong. It’s just a warning. It occurs because I used a case-insensitive identifier. That means that the term ‘xml’ shouldn’t be used as identifier because it overlaps with the XML-Class (same name only one time big and the other small letters).
    To get rid of that error just rename xml with something like myXML or so.