1 /*
  2  *Copyright (c) 2009, TellurianRing.com
  3  *All rights reserved.
  4  *
  5  *Redistribution and use in source and binary forms, with or without modification,
  6  *are permitted provided that the following conditions are met:
  7  *
  8  *   Redistributions of source code must retain the above copyright notice, this
  9  *   list of conditions and the following disclaimer.
 10  *   Redistributions in binary form must reproduce the above copyright notice,
 11  *   this list of conditions and the following disclaimer in the documentation
 12  *   and/or other materials provided with the distribution.
 13  *   Neither the name of the Organization (TellurianRing.com) nor the names of
 14  *   its contributors may be used to endorse or promote products derived from
 15  *   this software without specific prior written permission.
 16  *
 17  *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 18  *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 19  *WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 20  *DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 21  *ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 22  *(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 23  *LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 24  *ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 25  *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 26  *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 27  */
 28 /**
 29  * @class Groups some content together. Any action taken on a group is applied to all
 30  * of it's children.
 31  * @extends SceneContent
 32  * @example // New Group where the content starts at (10,10).
 33  * Group({
 34  *    x: 10, y: 10,
 35  *    content: [
 36  *       Graphic({ url: "./images/ball.png" }),
 37  *       Graphic({ url: "./images/beetleship.png", y: 20, x: 30 })
 38  *    ]
 39  * })
 40  * <div id="group_example_1"></div>
 41  * <script type="text/javascript">
 42  *    Stage({
 43  *       container_id: "group_example_1",
 44  *       width: 100, height: 100,
 45  *       update_time: 500,
 46  *       scene: Scene({
 47  *          content: [
 48  *             Group({
 49  *                x: 10, y: 10,
 50  *                content: [
 51  *                   Graphic({ url: "./images/ball.png" }),
 52  *                   Graphic({ url: "./images/beetleship.png", y: 20, x: 30 })
 53  *                ]
 54  *             })
 55  *          ]     
 56  *       })
 57  *    });
 58  * </script>
 59  * // In this example, the ball will display at (10,10), and the beetleship
 60  * // will display at (50,10).
 61  * @example // Moving the group.
 62  * myGroup.moveBy({ y: 10 });
 63  * // In this example, the ball will now display at (10, 20), and the beetleship
 64  * // will display at (50, 20).
 65  * <div id="group_example_2"></div>
 66  * <script type="text/javascript">
 67  *    var myGroup = Group({
 68  *                     x: 10, y: 10,
 69  *                     content: [
 70  *                        Graphic({ url: "./images/ball.png" }),
 71  *                        Graphic({ url: "./images/beetleship.png", y: 20, x: 30 })
 72  *                     ]
 73  *                  });
 74  *    Stage({
 75  *       container_id: "group_example_2",
 76  *       width: 100, height: 100,
 77  *       update_time: 500,
 78  *       scene: Scene({
 79  *          content: [ myGroup ]
 80  *       })
 81  *    });
 82  *    
 83  *    myGroup.moveBy({ y: 10 });
 84  * </script>
 85  * @param {Object} _details A JSON object with extra content.
 86  * <table cellpadding="0" cellspacing="1" border="0" class="constructor_details">
 87  *    <tr><th>Property</th> <th>Required</th> <th>Default</th></tr>
 88  *    <tr><td>content</td>  <td>no</td>       <td>new Array()</td></tr>
 89  * </table>
 90  */
 91 function Group(_details) { // {{{
 92    /** @constructs */
 93    function _Group(_details) { // {{{
 94       // Private Members {{{
 95       var content = check(_details.content, new Array());
 96       var name = _details.name;
 97       // }}}
 98       
 99       // Public Members {{{
100       /**
101        * Adds content to this group. Content added is first loaded then added to
102        * the the other content of this group at which point it will join the
103        * draw cycle.
104        * @param {SceneContent} _content The SceneContent to add to this group.
105        */
106       this.addContent = function(_content) {
107          _content.load(scene, this);
108          content.push(_content);
109       }
110       
111       this.draw = function(_context) {
112          // draw the groups contents to a different canvas.
113          var bounds = this.getBounds();
114          _context.save();
115          // translate the context to where the group will begin.
116          if(bounds.x > 0 || bounds.y > 0) {
117             _context.translate(bounds.x, bounds.y);
118          }
119          for(var index in content) {
120             var component = content[index];
121             if(component.isActive() && component.isVisible()) {
122                component.draw(_context);
123             }
124          }
125          _context.restore();
126       }
127       
128       /**
129        * Gets the content of this group. This implementation returns the actual
130        * content array, but should not be used to add content to this group.
131        * To add content to this group use the addContent function, which loads
132        * the content before adding it to the content array. Using this function
133        * to add content to this group will result in that content not being
134        * loaded, but being added to the draw cycle.
135        * @return The Content array.
136        */
137       this.getContent = function() { // {{{
138          return content;
139       } // }}} getContent
140       
141       this.load = function(_scene, _parent) { // {{{
142          this.loadBase(_scene, _parent);
143          for(var index in content) {
144             var component = content[index];
145             component.load(_scene, this);
146          }
147       } // }}} load
148       
149       this.update = function(_run_time) { // {{{
150          this.updateGroup(_run_time);
151       } // }}} update
152       /**
153        * Updates each of this groups content, and then calculates the groups
154        * cumulative bounds. This is mainly used by sub classes like Rotate and
155        * Translate groups.
156        */
157       this.updateGroup = function(_run_time) { // {{{
158          var bounds = this.getBounds();
159          for(var index in content) {
160             var component = content[index];
161             if(component.isActive()) {
162                component.update(_run_time);
163                var comp_bounds = component.getBounds();
164                bounds.w = Math.max(bounds.w, comp_bounds.x + comp_bounds.w);
165                bounds.h = Math.max(bounds.h, comp_bounds.y + comp_bounds.h);
166             }
167          }
168          this.setSize(bounds);
169          this.updateBase();
170       } // }}} updateGroup
171       // }}} Public Members
172    } // }}} _Group
173    SceneContent(_details).extend(_Group);
174    var theGroup = new _Group(_details);
175    return theGroup;
176 } // }}} Group
177 // These properties are for jEdit - Programmer's Text Editor.
178 // Load this file in jEdit to see what they do.
179 // ::folding=explicit:mode=javascript:noTabs=true:collapseFolds=4::
180