text: /*
  This file is part of Ext JS 4.2
  
  Copyright (c) 2011-2013 Sencha Inc
  
  Contact:  http://www.sencha.com/contact
  
  GNU General Public License Usage
  This file may be used under the terms of the GNU General Public License version 3.0 as
  published by the Free Software Foundation and appearing in the file LICENSE included in the
  packaging of this file.
  
  Please review the following information to ensure the GNU General Public License version 3.0
  requirements will be met: http://www.gnu.org/copyleft/gpl.html.
  
  If you are unsure which license is appropriate for your use, please contact the sales department
  at http://www.sencha.com/contact.
  
  Build date: 2013-05-16 14:36:50 (f9be68accb407158ba2b1be2c226a6ce1f649314)
  */
  /**
   * A composite Sprite handles a group of sprites with common methods to a sprite
   * such as `hide`, `show`, `setAttributes`. These methods are applied to the set of sprites
   * added to the group.
   *
   * CompositeSprite extends {@link Ext.util.MixedCollection} so you can use the same methods
   * in `MixedCollection` to iterate through sprites, add and remove elements, etc.
   *
   * In order to create a CompositeSprite, one has to provide a handle to the surface where it is
   * rendered:
   *
   *     var group = Ext.create('Ext.draw.CompositeSprite', {
   *         surface: drawComponent.surface
   *     });
   *                  
   * Then just by using `MixedCollection` methods it's possible to add {@link Ext.draw.Sprite}s:
   *  
   *     group.add(sprite1);
   *     group.add(sprite2);
   *     group.add(sprite3);
   *                  
   * And then apply common Sprite methods to them:
   *  
   *     group.setAttributes({
   *         fill: '#f00'
   *     }, true);
   */
  Ext.define('Ext.draw.CompositeSprite', {
  
      /* Begin Definitions */
  
      extend: 'Ext.util.MixedCollection',
      mixins: {
          animate: 'Ext.util.Animate'
      },
      autoDestroy: false,
      
      /* End Definitions */
      isCompositeSprite: true,
      constructor: function(config) {
          var me = this;
          
          config = config || {};
          Ext.apply(me, config);
  
          me.addEvents(
              /**
               * @event
               * @inheritdoc Ext.draw.Sprite#mousedown
               */
              'mousedown',
              /**
               * @event
               * @inheritdoc Ext.draw.Sprite#mouseup
               */
              'mouseup',
              /**
               * @event
               * @inheritdoc Ext.draw.Sprite#mouseover
               */
              'mouseover',
              /**
               * @event
               * @inheritdoc Ext.draw.Sprite#mouseout
               */
              'mouseout',
              /**
               * @event
               * @inheritdoc Ext.draw.Sprite#click
               */
              'click'
          );
          me.id = Ext.id(null, 'ext-sprite-group-');
          me.callParent();
      },
  
      // @private
      onClick: function(e) {
          this.fireEvent('click', e);
      },
  
      // @private
      onMouseUp: function(e) {
          this.fireEvent('mouseup', e);
      },
  
      // @private
      onMouseDown: function(e) {
          this.fireEvent('mousedown', e);
      },
  
      // @private
      onMouseOver: function(e) {
          this.fireEvent('mouseover', e);
      },
  
      // @private
      onMouseOut: function(e) {
          this.fireEvent('mouseout', e);
      },
  
      attachEvents: function(o) {
          var me = this;
          
          o.on({
              scope: me,
              mousedown: me.onMouseDown,
              mouseup: me.onMouseUp,
              mouseover: me.onMouseOver,
              mouseout: me.onMouseOut,
              click: me.onClick
          });
      },
  
      // Inherit docs from MixedCollection
      add: function(key, o) {
          var result = this.callParent(arguments);
          this.attachEvents(result);
          return result;
      },
  
      insert: function(index, key, o) {
          return this.callParent(arguments);
      },
  
      // Inherit docs from MixedCollection
      remove: function(o) {
          var me = this;
          
          o.un({
              scope: me,
              mousedown: me.onMouseDown,
              mouseup: me.onMouseUp,
              mouseover: me.onMouseOver,
              mouseout: me.onMouseOut,
              click: me.onClick
          });
          return me.callParent(arguments);
      },
      
      /**
       * Returns the group bounding box.
       * Behaves like {@link Ext.draw.Sprite#getBBox} method.
       * @return {Object} an object with x, y, width, and height properties.
       */
      getBBox: function() {
          var i = 0,
              sprite,
              bb,
              items = this.items,
              len = this.length,
              infinity = Infinity,
              minX = infinity,
              maxHeight = -infinity,
              minY = infinity,
              maxWidth = -infinity,
              maxWidthBBox, maxHeightBBox;
          
          for (; i < len; i++) {
              sprite = items[i];
              if (sprite.el && ! sprite.bboxExcluded) {
                  bb = sprite.getBBox();
                  minX = Math.min(minX, bb.x);
                  minY = Math.min(minY, bb.y);
                  maxHeight = Math.max(maxHeight, bb.height + bb.y);
                  maxWidth = Math.max(maxWidth, bb.width + bb.x);
              }
          }
          
          return {
              x: minX,
              y: minY,
              height: maxHeight - minY,
              width: maxWidth - minX
          };
      },
  
      /**
       * Iterates through all sprites calling `setAttributes` on each one. For more information {@link Ext.draw.Sprite}
       * provides a description of the attributes that can be set with this method.
       * @param {Object} attrs Attributes to be changed on the sprite.
       * @param {Boolean} redraw Flag to immediately draw the change.
       * @return {Ext.draw.CompositeSprite} this
       */
      setAttributes: function(attrs, redraw) {
          var i = 0,
              items = this.items,
              len = this.length;
              
          for (; i < len; i++) {
              items[i].setAttributes(attrs, redraw);
          }
          return this;
      },
  
      /**
       * Hides all sprites. If `true` is passed then a redraw will be forced for each sprite.
       * @param {Boolean} redraw Flag to immediately draw the change.
       * @return {Ext.draw.CompositeSprite} this
       */
      hide: function(redraw) {
          var i = 0,
              items = this.items,
              len = this.length;
              
          for (; i < len; i++) {
              items[i].hide(redraw);
          }
          return this;
      },
  
      /**
       * Shows all sprites. If `true` is passed then a redraw will be forced for each sprite.
       * @param {Boolean} redraw Flag to immediately draw the change.
       * @return {Ext.draw.CompositeSprite} this
       */
      show: function(redraw) {
          var i = 0,
              items = this.items,
              len = this.length;
              
          for (; i < len; i++) {
              items[i].show(redraw);
          }
          return this;
      },
  
      /**
       * Force redraw of all sprites.
       */
      redraw: function() {
          var me = this,
              i = 0,
              items = me.items,
              surface = me.getSurface(),
              len = me.length;
          
          if (surface) {
              for (; i < len; i++) {
                  surface.renderItem(items[i]);
              }
          }
          return me;
      },
  
      /**
       * Sets style for all sprites.
       * @param {String} style CSS Style definition.
       */
      setStyle: function(obj) {
          var i = 0,
              items = this.items,
              len = this.length,
              item, el;
              
          for (; i < len; i++) {
              item = items[i];
              el = item.el;
              if (el) {
                  el.setStyle(obj);
              }
          }
      },
  
      /**
       * Adds class to all sprites.
       * @param {String} cls CSS class name
       */
      addCls: function(obj) {
          var i = 0,
              items = this.items,
              surface = this.getSurface(),
              len = this.length;
          
          if (surface) {
              for (; i < len; i++) {
                  surface.addCls(items[i], obj);
              }
          }
      },
  
      /**
       * Removes class from all sprites.
       * @param {String} cls CSS class name
       */
      removeCls: function(obj) {
          var i = 0,
              items = this.items,
              surface = this.getSurface(),
              len = this.length;
          
          if (surface) {
              for (; i < len; i++) {
                  surface.removeCls(items[i], obj);
              }
          }
      },
      
      /**
       * Grab the surface from the items
       * @private
       * @return {Ext.draw.Surface} The surface, null if not found
       */
      getSurface: function(){
          var first = this.first();
          if (first) {
              return first.surface;
          }
          return null;
      },
      
      /**
       * Destroys this CompositeSprite.
       */
      destroy: function(){
          var me = this,
              surface = me.getSurface(),
              destroySprites = me.autoDestroy,
              item;
              
          if (surface) {
              while (me.getCount() > 0) {
                  item = me.first();
                  me.remove(item);
                  surface.remove(item, destroySprites);
              }
          }
          me.clearListeners();
      }
  });
  