ActionScript 3 Accordion Content

ActionScript 3 Vertical & Horizontal Accordion Menu with support for columns of content.

This example extends and supersedes an earlier version of this file I wrote about a year ago. I always wanted to make a horizontal version and extend the class, making it more flexible and useful to people.

As was the previous menu, this menu is a Class based ActionScript 3 Accordion Menu, with either a rollOver/RollOff activation scheme for a onRelease activation scheme. I also added in a better extended event class which allows you to control, or respond to all menu activity via events.

Class Features

  • Vertical or Horizontal Menu Orientation
  • Visible or invisible Menu Bar
  • Supports parsing functions passed to each menu item
  • Custom Menu Bar Assets
  • Option for persistent Menu Panels
  • Menu Spacing
  • Menu text position
  • MenuBar colour / RollOver/Off colour
  • Menu text format
  • Menu tween speed
  • Menu easing type
  • MenuBar width, height, visibility
  • Menu Click behaviour
  • Disable / Enable Menu
  • Open Particular Panels
  • Menu attributes are applicable on a per menu item basis
  • etc, etc.

View Example
http://noponies.com/dev/as3_accordion/

Source Files
Donator only file!
If you want a less capable version of this file, you can download this; http://www.blog.noponies.com/archives/39

Dependencies
TweenLite - http://www.tweenlite.com

Class ActionScript
This is just the “manager class”, and not the entire NpAccordion Class Package.

/* AS3
* Copyright 2008 noponies.
*/


package noponies.ui{
  import flash.display.Sprite;
  import flash.display.DisplayObject;
  import flash.display.Shape;
  import flash.display.Stage;
  import flash.events.MouseEvent;
  import flash.events.Event;
  import flash.text.TextField;
  import flash.text.TextFieldAutoSize;
  import flash.text.TextFieldType;
  import flash.text.TextFormat;
  import flash.text.AntiAliasType;
  import fl.motion.easing.*;
  //non internal imports
  import gs.TweenLite;
  import noponies.ui.events.NpAccordionEvent;
  import noponies.ui.NpAccordionPaneV;
  import noponies.ui.NpAccordionPaneH;
 
    /**
    *   <strong>NpAccordion</strong>
    *   <p>This menu system was written as a means to display content in a condensed manner. Menus can be either vertical or horizontal. Supports mulitple columns.</p>
    *   <p>Simple XML based accordion menu. Menu acts as a content space minimiser, with content hidden behind menu bar items. Content
    * slides into view when the menu item is clicked on. However, you can pass it any display objects, derived how you like. </p>
    * <p>Menu supports parsing function calls passed as a string value , along with parameter support for these functions. This is useful for perhaps
    * calling a function on the parent timeline of the menu. Menu also supports a standard URL call passed to it.</p>
    * <p>Menu supports any DisplayObject. Loaded swfs can contain their own interactivity. </p>
    * <p>Menu supports using either the whole menu or just the menu bar as the mechansim for sliding the menu up and down. Generally it is better to only use
    * the bar if you want to include interactivity in the menu items.</p>
    * <p>Positioning menu:To create a column, or otherwise change menu item positions, set either the menuPosX or menuPosY values, like so, menuInstanceVarName.menuPosX = newValue</p>
    * <p>Menu supports custom events, so that individual menu instances can be targetted. Doing so relies on the <code>NpAccordionEvent</code> Class, which allows for the passing
    * of parameters to each menu item. This param is checked against the ID var of each menu, if they match, then the menu acts on the event.</p>
    * <p>Class requires TweenLite <a href="http://blog.greensock.com/tweenliteas3" target="_blank">http://blog.greensock.com/tweenliteas3</a><p>
    * <b>Author:</b> noponies - <a href="http://www.blog.noponies.com/" target="_blank">www.blog.noponies.com</a><br />
    *   <b>Class version:</b> 1<br />
    *   <b>Actionscript version:</b> 3.0 Player Version 9.0.28<br />
    *   <b>Copyright:</b>
    *   Creative Commons AttCreative Commons Attribution 3.0 New Zealand License<br />
    *   <a href="http://creativecommons.org/licenses/by/3.0/nz/" target="_blank">http://creativecommons.org/licenses/by/3.0/nz/</a><br />
    *   You can use this class how you like, except as a base for Flash Components or for Flash Template sites.<br />
    *   <br />
    *   <b>Date:</b> 17 July 2008<br />
    */


  public class NpAccordion extends Sprite {
   
    private var menuOrientation:String = "horizontal"
    private var clickMode:Boolean = true
    private var counter:int
    private var menuItems:Array
    private var menuPosY:int = 0;
    private var menuPosX:int = 0;
   
    private var menuPadding:int = 5;//space between menu items
    private var barHeight:int = 10//default
    private var barWidth:int = 10
    private var menuTxtFormat:TextFormat
    private var menuEnabled:Boolean =true//defaut, is the menu as a whole disable from mouse interactivity
    private var speed:Number = .5;//menu transition speed - in seconds
    private var useWholeMenu:Boolean = false;//default
    private var menuColour:uint = 0x000000;//menu bars colour
    private var menuAlpha:Number = 1//default
    private var useHighLighting:Boolean = true;//change colours of bar on rollOver?
    private var menuHighlightColour:int = 0xCCCCCC;//menu rollover colour
    private var easeType:Function = fl.motion.easing.Linear.easeNone //default ease type
   
    //action handling
    private var contentHasAction:Boolean = true//default
    private var contentActionScope:Object //scope that actions run within when applying actions internally
    private var handleActionsExternally:Boolean = true//default

   
    /**
     *  Get / Set whether or not to change the colour of the menu bar with a rollOver. A value of <code>true</code> enables this feature.
     *  @param Boolean
     *  @default true
     *  @return Boolean
     */

    public function get setMenuX():int {
      return menuPosX;
    }
    /**
    * @private
    */

    public function set setMenuX(newMenuPosX:int):void {
      menuPosX = newMenuPosX;
    }
    /**
     *  Get / Set whether or not to change the colour of the menu bar with a rollOver. A value of <code>true</code> enables this feature.
     *  @param Boolean
     *  @default true
     *  @return Boolean
     */

    public function get setMenuY():int {
      return menuPosY;
    }
    /**
    * @private
    */

    public function set setMenuY(newMenuPosY:int):void {
      menuPosY = newMenuPosY;
    }
    /**
     *  Get / Set the padding between each menu item.
     *  @param int
     *  @default 5
     *  @return int
     */

    public function get menuSpacing():int {
      return menuPadding;
    }
    /**
    * @private
    */

    public function set menuSpacing(newMenuPadding:int):void {
      menuPadding = newMenuPadding;
    }  
    /**
     *  Get / Set if the menus respond to interactivity. Use this property when loading a menu set and you want to disable a user clicking on menu items until all
     *  content has loaded, or some other event occurs. If you set this property, dispatch a <code>NpAccordionEvent.ENABLE_MENU</code> event to enable menu interactivity globally.
     *  @param Boolean
     *  @default true
     *  @return Boolean
     *  @see noponies.accordion.events.NpAccordionEvent#DISABLE_MENU
     *  @see noponies.accordion.events.NpAccordionEvent#ENABLE_MENU
     */

    public function get menusEnabled():Boolean {
      return menuEnabled;
    }
    /**
    * @private
    */

    public function set menusEnabled( newMenuEnabled:Boolean):void {
      menuEnabled = newMenuEnabled;
    }
    /**
     *  Get / Set whether or not to change the colour of the menu bar with a rollOver. A value of <code>true</code> enables this feature.
     *  @param Boolean
     *  @default true
     *  @return Boolean
     */

    public function get highLightMenuBar():Boolean {
      return useHighLighting;
    }
    /**
    * @private
    */

    public function set highLightMenuBar(newHigh:Boolean):void {
      useHighLighting = newHigh;
    }
    /**
     *  Get / Set the colour to use when you have enabled the <code>highLightMenu<code> property.
     *  @param uint
     *  @default 0xCCCCCC (light grey)
     *  @return uint
     */

    public function get highLightColour():uint {
      return menuHighlightColour;
    }
    /**
    * @private
    */

    public function set highLightColour(newCol:uint):void {
      menuHighlightColour = newCol;
    }
    /**
     *  Get / Set the tween speed of the menus opening and closing.
     *  @param Number representing the speed in seconds for menu opening and closing tweens.
     *  @default .5
     *  @return Number
     */

    public function get tweenSpeed():Number {
      return speed;
    }
    /**
    * @private
    */

    public function set tweenSpeed(newSpeed:Number):void {
      speed = newSpeed;
    }
    /**
     *  Get / Set the height of the menu bar in pixels.
      * <p>The impact of this setting depends on how you are displaying your menus. If you have chosen to display a <em>horizontal</em> (menu slides across x axis)
     *  menu, then this setting controls how far across the side of your content the menuBar displays.
     *  If you want it to match the height of your content, set it to <code>0</code>. If you are displaying your menu as a  <em>vertical</em> menu, then this setting controls the visible height
     *  of the menuBar. Setting the menuBarAlpha to <code>0</code> will make your menuBar invisible.
     *  @param int
     *  @default 10
     *  @return int
     *  @see #menuBarAlpha
     *  @see #menuBarWidth
     */

    public function get menuBarHeight():int {
      return barHeight;
    }
    /**
    * @private
    */

   
    public function set menuBarHeight(newBarHeight:int):void {
      barHeight = newBarHeight;
    }
    /**
     *  Get / Set the width of the menu bar in pixels.
     *  <p>The impact of this setting depends on how you are displaying your menus. If you have chosen to display a <em>horizontal</em> (menu slides across x axis)
     *  menu, then this setting controls the visible width of the menuBar. If you are displaying your menu as a  <em>vertical</em> menu, then this setting
     *  controls how far across the top of your content the menuBar displays. If you want it to match the width of your content, set it to <code>0</code>.
     *  Setting the menuBarAlpha to <code>0</code> will make your menuBar invisible.
     *  @param int
     *  @default 10
     *  @return int
     *  @see #menuBarHeight
     *  @see #menuBarAlpha
     */

    public function get menuBarWidth():int {
      return barWidth;
    }
    /**
    * @private
    */

    public function set menuBarWidth(newBarWidth:int):void {
      barWidth = newBarWidth;
    }
    /**
     *  Get / Set the colour of the menu bar.
     *  @param uint
     *  @default 0x000000 (black)
     *  @return uint
     */

    public function get menuBarColour():uint {
      return menuColour;
    }
    /**
    * @private
    */

    public function set menuBarColour(newMenuColour:uint):void {
      menuColour = newMenuColour;
    }
    /**
     *  Get / Set the alpha levels of the menu bar.
     *  <p>A technique you can employ here is to set the menu bars alpha to 0, so that your content will be visible. You may also wish to adjust the <code>menuBarHeight</code> property, as this will
     *  control how much of your content is visible.</p>
     *  @param Number
     *  @default 1
     *  @return Number
     *  @see #menuBarWidth
     *  @see #menuBarHeight
     */

    public function get menuBarAlpha():Number {
      return menuAlpha;
    }
    /**
    * @private
    */

    public function set menuBarAlpha(newMenuAlpha:Number):void {
      menuAlpha = newMenuAlpha;
    }
   
    /**
     *  Get / Set how a the menu item and menu content respond to clicks. A value of <code>false</code> enables mouseEvent.CLICK interactivity on the menu bar alone. This is the setting you would use if your content
     *  itself had interactivity. A value of <code>true</code> enables mouseEvent.CLICK interactivity on the entire menu item.
     *  @param Boolean
     *  @default false
     *  @return Boolean
     */

    public function get globalMenuClick():Boolean {
      return useWholeMenu;
    }
    /**
    * @private
    */

    public function set globalMenuClick(newUseWholeMenu:Boolean):void {
      useWholeMenu = newUseWholeMenu;
    }
    /**
     *  Get / Set how a the menu will handle any actions passed to it. A value of <code>true</code> will dispatch all actions via the <code>NpAccordionEvent.PRESS</code> event. You can access this events
     *  <code>menuAction</code> property to parse what action the menu item contained. This property is sent in String form. A value of <code>false</code> will make the menu run the actions internally.
     *  @param Boolean
     *  @default true
     *  @return Boolean
     *  @see #actionScope
     */

    public function get delegateActions():Boolean {
      return handleActionsExternally;
    }
    /**
    * @private
    */

    public function set delegateActions(newDispatchMenuActions:Boolean):void {
      handleActionsExternally = newDispatchMenuActions;
    }
    /**
     *  Change the way actions are fired off a menu item. Setting this value to <code>true</code> will make the contentItem itself, rather than the menu bar fire any actions you may have set.
     *  A value of <code>false</code> will make menu actions fire from a CLICK on the menu bar. This means that a user has to first click on the bar to open the menu item, then click on any content it may have.
     *  @param Boolean
     *  @default true
     *  @return Boolean
     *  @see #actionScope
     *  @see #delegateActions
     */

    public function get contentActions():Boolean {
      return contentHasAction;
    }
    /**
    * @private
    */

    public function set contentActions(newContentAction:Boolean):void {
      contentHasAction = newContentAction;
    }
    /**
     *  Set the scope that internally applied actions run within. By default this is set to the parent object of each menu item. Set this property of you want actions to run internally in another scope.
     *  @param Object
     *  @default menuItem.parent
     *  @return Object
     *  @see #delegateActions
     */

    public function get actionScope():Object {
      return contentActionScope;
    }
    /**
    * @private
    */

    public function set actionScope(newActionScope:Object):void {
      contentActionScope = newActionScope;
    }
    /**
     *  Set the textformat that the menu items will use for their text display. If you do not pass in a TextFormat Object the class defaults to using 10 pt, white _sans for any menu text. By default the menu
     *  textField is set to use embedded fonts. This setting affects the defaultTextFormat property of the menus textField. So, once this is set, future text assignments will inherit that text format.
     *  @param Textformat
     *  @default null
     *  @return
     */

    public function set menuTextFormat(newFormat:TextFormat):void {
      menuTxtFormat = newFormat;
    }
    /**
     *  Set the ease type that the menus use when moving. This parameter is in the form of a <code>fl.motion.easing.Elastic.easeInOut</code>. The default is a <code>fl.motion.easing.Linear.easeNone</code>, or no easing.
     *  @param Function
     *  @default fl.motion.easing.Linear.easeNone
     *  @return
     */

    public function set menuEaseType(newEaseType:Function):void {
      easeType = newEaseType;
    }
    /**
     *  Get the current menu items as an array of Class Objects representing each menu item created by this Class.
     *  @return Array
     */

    public function get currentMenuArray():Array {
      return menuItems
    }
   
    //--------------------------------------
    // CONSTRUCTOR
    //--------------------------------------
    /**
     *  Please review the various Getter / Setter Methods for controlling the look, feel and behaviour of the Accordion Menu.
     *  <p>To control the properties of individual menu items, set the menu items properties before you call the <code>addPanel()</code> method!</p>
     *  <p>Make sure you pay attention to the <code>menuBarHeight</code> and the <code>menuBarWidth</code> properties when switching between vertical or horizontally displaying menus.</p>
     *  <p>Should you need access to the current active menu items ID, or its menuBar Sprite or menuBar textField please review the various events and event parameters that allow for this access</p>
     *  @param mouseMode String. <strong>Optional (Default: click)</strong> Controls the click or rollOver action of the menu. A value of <code>click</code> makes the menu open in response to Mouse Clicks. A value of <code>rollover</code> makes the menu open and close in reponse to
     *  a user rolling over and off individual menu items.
     *  @param menuOrientation String. <strong>Optional (Default: vertical)</strong> String representing the click action of the menu item. This can be either a http URL or a function with parameters. In this format <code>Function Name, param, param</code>
     *  @see #globalMenuClick
     *  @see #menusEnabled
     *  @see #menuColour
     *  @see #menuBarAlpha
     *  @see #menuBarHeight
     *  @see #menuBarWidth
     *  @see #menuSpacing
     *  @see #tweenSpeed
     *  @see #actionScope
     *  @see #delegateActions
     *  @see #contentActions
     *  @see #menuTextFormat
     *  @see #menuEaseType
     */

    public function NpAccordion(mouseMode:String ="click", menuOrientation:String ="vertical") {
      //validate menu mode
      switch (mouseMode) {
        case "click" :
          clickMode = true
          break;
        case  "rollover" :
          clickMode = false
          break
        default:
          throw new Error("Problem :The mouseMode parameter passed is incorrect. It must be either 'click' or 'rollover'!"+ " You passed '"+mouseMode+"'");
      }
      //validate menuOrientation
      switch (menuOrientation) {
        case "horizontal" :
          this.menuOrientation = menuOrientation
          break;
        case  "vertical" :
          this.menuOrientation = menuOrientation
          break
        default:
          throw new Error("Problem :The menuOrientation parameter passed is incorrect. It must be either 'horizontal' or 'vertical'!"+ " You passed '"+menuOrientation+"'");
      }
      menuItems = []
      addEventListener(Event.REMOVED_FROM_STAGE, handleStageRemoval)
    }
    //--------------------------------------
    // ADDPANEL METHOD - ADD A MENU PANEL TO THE ACCORDION MENU
    //-------------------------------------- 
    /**
     *  The addPanel Method adds an accordion panel (via an instance of the NpAccordionPane Class) to an instance of the NpAccordion Class.
     *  <p>To control the properties of individual menu items, set the menu items properties before you call the <code>addPanel()</code> method!</p>
     *  @param loadedContent DisplayObject. The content you want to place within an NpAccordion Menu item.
     *  @param titleText String. <strong>Optional</strong> String representing the text of the menu bar.
     *  @param action String. <strong>Optional</strong> String representing the click action of the menu item. This can be either a http URL or a function with parameters. In this format <code>Function Name, param, param</code>
     *  @see #globalMenuClick
     *  @see #menusEnabled
     *  @see #menuColour
     *  @see #menuBarAlpha
     *  @see #menuBarHeight
     *  @see #menuBarWidth
     *  @see #menuSpacing
     *  @see #tweenSpeed
     *  @see #actionScope
     *  @see #delegateActions
     *  @see #contentActions
     *  @see #menuTextFormat
     *  @see #menuEaseType
     */

    public function addPanel(loadedContent:DisplayObject, titleText:String="", action:String=""):void {

      var ClassSwitch:Class
      if(menuOrientation=="vertical"){
        ClassSwitch = NpAccordionPaneV
      }else{
        ClassSwitch = NpAccordionPaneH
      }
      var menuItem:Object = new ClassSwitch(loadedContent, counter, titleText, action);

      //set menu properties before it draws itself to stage
      menuItem._clickMode = clickMode
      menuItem.x = menuPosX
      menuItem.y = menuPosY
      menuItem._barHeight = barHeight
      menuItem._barWidth = barWidth
      menuItem._menuTxtFormat = menuTxtFormat
      menuItem._menuEnabled = menuEnabled
      menuItem._speed = speed
      menuItem._useWholeMenu = useWholeMenu
      menuItem._menuColour = menuColour
      menuItem._menuAlpha = menuAlpha
      menuItem._useHighLighting = useHighLighting
      menuItem._menuHighlightColour = menuHighlightColour
      menuItem._easeType = easeType
      //action handling
      menuItem._contentHasAction = contentHasAction
      menuItem._contentActionScope = contentActionScope
      menuItem._handleActionsExternally = handleActionsExternally
     
      if(menuOrientation=="vertical"){
        menuPosY += (barHeight+menuPadding);//positioning of menu, vertically = barheight + menu padding
      }else{
        menuPosX += (barWidth+menuPadding);//positioning of menu, horizontally = barwidth + menu padding
      }
     
      addChild(DisplayObject(menuItem))
      //push menu instances into array
      menuItems.push(menuItem)
      //increment counter
      counter++

    }
   
    //--------------------------------------
    // OPENPANEL METHOD - OPEN A PANEL IN THE ACCORDION MENU
    //--------------------------------------     
    /**
    *   This public method will open a particular menu panel.
    * @param int Representing the menu panel you would like to open. Menus are stored as a zero based array. Some error checking is conducted to test if the menu requested is within the range of available menu items.
    * <p>The same effect can be achieved by dispatching a <code>NpAccordionEvent.EXPAND_MENU</code> event at the Accordion Class instance.</p>
    * @see noponies.accordion.events.NpAccordionEvent#EXPAND_MENU
    * @return
    */

    public function openPanel(menuToOpen:int):void {
      if(menuToOpen>menuItems.length || menuToOpen<0){
        throw new Error("Passed menu index is out of bounds!");
      }else{
        menuItems[menuToOpen].openPane()
      }
    }
   
    //--------------------------------------
    // CLOSEPANEL METHOD - CLOSE ANY OPEN PANEL IN THE ACCORDION MENU
    //-------------------------------------- 
    /**
    *   This public method will close any open menu panels.
    * <p>The same effect can be achieved by dispatching a <code>NpAccordionEvent.RESETALL</code> event at the Accordion Class instance.</p>
    * @see noponies.accordion.events.NpAccordionEvent#RESETALL
    * @return
    */

    public function closePanel():void {
      dispatchEvent(new NpAccordionEvent(NpAccordionEvent.RESETALL,true, false));
    }
   
    //--------------------------------------
    // REMOVED FROM STAGE HANDLER
    //-------------------------------------- 
    private function handleStageRemoval(event:Event):void {
      menuItems = []
      counter=0
    }
  }
}

14 Responses to “ActionScript 3 Accordion Content”


  1. 1 smith

    Some files link doesn’t work.

  2. 2 oliver_l1

    Cool menu! Custom menuBar assets would be a nice additional feature.

  3. 3 Dale

    Smith,

    works fine for me.

  4. 4 pete

    hey dale nice post…(still waiting for the full screen vid…though…)…does this load interactive swfs? ie, contact forms, interactive foto galleries etc?

  5. 5 Dale

    Pete,

    Yeah, it loads any DisplayObject..So whatever you want.

    The fullScreenVid is finished, and in the donators section.

  6. 6 Darío Gutiérrez

    Chidooo menu!! works for me too!! Thanks for sharing Dale, Best regards!

  7. 7 pete

    thx dale….couldnt donate much right now as im freakin broke right now but i really learn alot from your code esspecially as im still trying to get m head around as3 ……. the next job i get ill be able to donate more generously.thx for your hard work

  8. 8 Andre

    When I embed as3Accord.swf in a other flash file. How can I reference the Resetall function from that flash file?

    main swf:
    var menuloader:Loader = new Loader;
    menuloader.load(new URLRequest(”menu/as3Accord.swf”)); //load the menu
    container.addChild(menuloader);

    resetbtn.addEventListener(MouseEvent.CLICK, reset);

    function reset(evt:MouseEvent)
    {
    menuloader.parent.root[”resetMenu”] (evt) //????? what do I put here
    }

  9. 9 Dale

    Andre,

    I think you have posted this question under the wrong Accordion example.

    But you should just be able to dispatch the resetAll event and the accordion should pick it up.

    dispatchEvent(new Event(”resetMenus”,true));

  10. 10 anthony

    amazing work as usual …

    i’m newish to AS2 and just starting to acclimate to AS3 so this script is like a crash course …

    am i crazy in thinking that another xml variable can be passed into the menu? i would really love to have some text OVER the image once it appears … is this possible???

    thanks fer any insight

  11. 11 Dale

    Anthony,

    It does not do that by default. You would have to add that in, pretty easy to do so however.

  12. 12 Andre

    Hi Dale,

    Thanks for your reply. And you’re right, My previous question concerned the other accordionmenu. But I have another question, which is related to my last post, so to make things tidy, l’ll post it here too.

    How do I approach a Listener which is in a swf loaded by the menu, when the menu is loaded in other swf?
    main.swf (dispatchEvent “Changer” => as3accord.swf => textfield.swf (Listens to “Changer”)

    code:
    Main.swf
    var menuloader:Loader = new Loader;
    menuloader.load(new URLRequest(”menu/as3Accord.swf”)); //load the menu
    container.addChild(menuloader);

    var Text2Change:String = “blabla”;
    changebtn.addEventListener(MouseEvent.CLICK, reset);

    function reset(evt:MouseEvent)
    {
    menuloader.content.dispatchEvent(”Changer”,true);
    }

    Textfield.swf
    code:
    addEventListener(”Changer”, CreateTextfield);

    function CreateTextfield(e:Event)
    {
    trace(MovieClip(parent.parent.parent).Text2Change);
    }

    I can’t get it to work (tried to add and remove more .parent). Can I interact like this directly or do I have to add some listeners and dispatchers in the menu too so it passes it along? I saw an example of a function in the menuloaded swf, which was linked to a function in the root by declaring it as a public function in the class. Basicly I need this, but the other way around, a function declared in the menuloaded swf, thats steered by a string in the main swf. (I’m making a button that changes the information textfield in the menuloaded swf)

    I know I stray away a bit, but hopefully can you help me?

    Thanks in advance.

  13. 13 Andre

    Solved it. Created another class to dispatch events too :)

  14. 14 Dale

    Andre,

    Great. I saw your posts on kirupa.Glad you got it sorted.

Leave a Reply