1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3 
  4  http://www.cocos2d-x.org
  5 
  6  Permission is hereby granted, free of charge, to any person obtaining a copy
  7  of this software and associated documentation files (the "Software"), to deal
  8  in the Software without restriction, including without limitation the rights
  9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  copies of the Software, and to permit persons to whom the Software is
 11  furnished to do so, subject to the following conditions:
 12 
 13  The above copyright notice and this permission notice shall be included in
 14  all copies or substantial portions of the Software.
 15 
 16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  THE SOFTWARE.
 23  ****************************************************************************/
 24 /**
 25  * layoutBackGround color type
 26  * @type {Object}
 27  */
 28 ccs.LayoutBackGroundColorType = {
 29     none: 0,
 30     solid: 1,
 31     gradient: 2
 32 };
 33 
 34 /**
 35  * Layout type
 36  * @type {Object}
 37  */
 38 ccs.LayoutType = {
 39     absolute: 0,
 40     linearVertical: 1,
 41     linearHorizontal: 2,
 42     relative: 3
 43 };
 44 
 45 /**
 46  * Layout type
 47  * @type {Object}
 48  */
 49 ccs.LayoutClippingType = {
 50     stencil: 0,
 51     scissor: 1
 52 };
 53 
 54 ccs.BACKGROUNDIMAGEZ = -2;
 55 ccs.BACKGROUNDCOLORRENDERERZ = -2;
 56 /**
 57  * Base class for ccs.Layout
 58  * @class
 59  * @extends ccs.Widget
 60  */
 61 ccs.Layout = ccs.Widget.extend(/** @lends ccs.Layout# */{
 62     _clippingEnabled: null,
 63     _backGroundScale9Enabled: null,
 64     _backGroundImage: null,
 65     _backGroundImageFileName: null,
 66     _backGroundImageCapInsets: null,
 67     _colorType: null,
 68     _bgImageTexType: null,
 69     _colorRender: null,
 70     _gradientRender: null,
 71     _color: null,
 72     _startColor: null,
 73     _endColor: null,
 74     _alongVector: null,
 75     _opacity: null,
 76     _backGroundImageTextureSize: null,
 77     _layoutType: null,
 78     _doLayoutDirty: false,
 79     _clippingRectDirty: false,
 80     _clippingType : null,
 81     _clippingStencil: null,
 82     _handleScissor: false,
 83     _scissorRectDirty: false,
 84     _clippingRect: null,
 85     _clippingParent: null,
 86     _backGroundImageColor:null,
 87     _backGroundImageOpacity:null,
 88     ctor: function () {
 89         ccs.Widget.prototype.ctor.call(this);
 90         this._clippingEnabled = false;
 91         this._backGroundScale9Enabled = false;
 92         this._backGroundImage = null;
 93         this._backGroundImageFileName = "";
 94         this._backGroundImageCapInsets = cc.RectZero();
 95         this._colorType = ccs.LayoutBackGroundColorType.none;
 96         this._bgImageTexType = ccs.TextureResType.local;
 97         this._colorRender = null;
 98         this._gradientRender = null;
 99         this._color = cc.white();
100         this._startColor = cc.white();
101         this._endColor = cc.white();
102         this._alongVector = cc.p(0, -1);
103         this._opacity = 255;
104         this._backGroundImageTextureSize = cc.SizeZero();
105         this._layoutType = ccs.LayoutType.absolute;
106         this._widgetType = ccs.WidgetType.container;
107         this._doLayoutDirty = true;
108         this._clippingRectDirty = true;
109         this._clippingType = ccs.LayoutClippingType.stencil;
110         this._clippingStencil = null;
111         this._handleScissor = false;
112         this._scissorRectDirty = false;
113         this._clippingRect = cc.rect(0, 0, 0, 0);
114         this._clippingParent = null;
115         this._backGroundImageColor = cc.c3b(255, 255, 255);
116         this._backGroundImageOpacity = 255;
117     },
118     init: function () {
119         if (cc.Node.prototype.init.call(this)){
120             this._layoutParameterDictionary = {};
121             this._widgetChildren = [];
122             this.initRenderer();
123             this.ignoreContentAdaptWithSize(false);
124             this.setSize(cc.SizeZero());
125             this.setBright(true);
126             this.setAnchorPoint(0, 0);
127             this.initStencil();
128             return true;
129         }
130         return false;
131     },
132     initStencil : null,
133     _initStencilForWebGL:function(){
134         this._clippingStencil = cc.DrawNode.create();
135         ccs.Layout._init_once = true;
136         if (ccs.Layout._init_once) {
137             cc.stencilBits = cc.renderContext.getParameter(cc.renderContext.STENCIL_BITS);
138             if (cc.stencilBits <= 0)
139                 cc.log("Stencil buffer is not enabled.");
140             ccs.Layout._init_once = false;
141         }
142     },
143     _initStencilForCanvas: function () {
144         this._clippingStencil = cc.DrawNode.create();
145         var locEGL_ScaleX = cc.EGLView.getInstance().getScaleX(), locEGL_ScaleY = cc.EGLView.getInstance().getScaleY();
146         var locContext = cc.renderContext;
147         var stencil = this._clippingStencil;
148         stencil.draw = function () {
149             for (var i = 0; i < stencil._buffer.length; i++) {
150                 var element = stencil._buffer[i];
151                 var vertices = element.verts;
152                 var firstPoint = vertices[0];
153                 locContext.beginPath();
154                 locContext.moveTo(firstPoint.x * locEGL_ScaleX, -firstPoint.y * locEGL_ScaleY);
155                 for (var j = 1, len = vertices.length; j < len; j++)
156                     locContext.lineTo(vertices[j].x * locEGL_ScaleX, -vertices[j].y * locEGL_ScaleY);
157             }
158         }
159     },
160 
161     /**
162      * Adds a widget to the container.
163      * @param {ccs.Widget} widget
164      * @param {Number} zOrder
165      * @param {Number} tag
166      */
167     addChild: function (widget, zOrder, tag) {
168         if(!(widget instanceof ccs.Widget)){
169             throw "the child add to Layout  must a type of cc.Widget";
170         }
171         this.supplyTheLayoutParameterLackToChild(widget);
172         ccs.Widget.prototype.addChild.call(this, widget, zOrder, tag);
173         this._doLayoutDirty = true;
174     },
175 
176     /**
177      * Remove widget
178      * @param {ccs.Widget} widget
179      * @param {Boolean} cleanup
180      */
181     removeChild:function(widget,cleanup){
182         ccs.Widget.prototype.removeChild.call(this, widget,cleanup);
183         this._doLayoutDirty = true;
184     },
185 
186     /**
187      * Remove all widget
188      * @param {Boolean} cleanup
189      */
190     removeAllChildren:function(cleanup){
191         ccs.Widget.prototype.removeAllChildren.call(this, cleanup);
192         this._doLayoutDirty = true;
193     },
194 
195     /**
196      * Gets if layout is clipping enabled.
197      * @returns {Boolean}
198      */
199     isClippingEnabled: function () {
200         return this._clippingEnabled;
201     },
202 
203     visit: function (ctx) {
204         if (!this._enabled) {
205             return;
206         }
207         if (this._clippingEnabled) {
208             switch (this._clippingType) {
209                 case ccs.LayoutClippingType.stencil:
210                     this.stencilClippingVisit(ctx);
211                     break;
212                 case ccs.LayoutClippingType.scissor:
213                     this.scissorClippingVisit(ctx);
214                     break;
215                 default:
216                     break;
217             }
218         }
219         else {
220             cc.Node.prototype.visit.call(this,ctx);
221         }
222     },
223 
224     sortAllChildren: function () {
225         ccs.Widget.prototype.sortAllChildren.call(this);
226         this.doLayout();
227     },
228 
229     stencilClippingVisit : null,
230 
231     _stencilClippingVisitForWebGL: function (ctx) {
232         var gl = ctx || cc.renderContext;
233 
234         // if stencil buffer disabled
235         if (cc.stencilBits < 1) {
236             // draw everything, as if there where no stencil
237             cc.Node.prototype.visit.call(this, ctx);
238             return;
239         }
240 
241         // return fast (draw nothing, or draw everything if in inverted mode) if:
242         // - nil stencil node
243         // - or stencil node invisible:
244         if (!this._clippingStencil || !this._clippingStencil.isVisible()) {
245             return;
246         }
247 
248         // store the current stencil layer (position in the stencil buffer),
249         // this will allow nesting up to n CCClippingNode,
250         // where n is the number of bits of the stencil buffer.
251         ccs.Layout._layer = -1;
252 
253         // all the _stencilBits are in use?
254         if (ccs.Layout._layer + 1 == cc.stencilBits) {
255             // warn once
256             ccs.Layout._visit_once = true;
257             if (ccs.Layout._visit_once) {
258                 cc.log("Nesting more than " + cc.stencilBits + "stencils is not supported. Everything will be drawn without stencil for this node and its childs.");
259                 ccs.Layout._visit_once = false;
260             }
261             // draw everything, as if there where no stencil
262             cc.Node.prototype.visit.call(this, ctx);
263             return;
264         }
265 
266         ///////////////////////////////////
267         // INIT
268 
269         // increment the current layer
270         ccs.Layout._layer++;
271 
272         // mask of the current layer (ie: for layer 3: 00000100)
273         var mask_layer = 0x1 << ccs.Layout._layer;
274         // mask of all layers less than the current (ie: for layer 3: 00000011)
275         var mask_layer_l = mask_layer - 1;
276         // mask of all layers less than or equal to the current (ie: for layer 3: 00000111)
277         var mask_layer_le = mask_layer | mask_layer_l;
278 
279         // manually save the stencil state
280         var currentStencilEnabled = gl.isEnabled(gl.STENCIL_TEST);
281         var currentStencilWriteMask = gl.getParameter(gl.STENCIL_WRITEMASK);
282         var currentStencilFunc = gl.getParameter(gl.STENCIL_FUNC);
283         var currentStencilRef = gl.getParameter(gl.STENCIL_REF);
284         var currentStencilValueMask = gl.getParameter(gl.STENCIL_VALUE_MASK);
285         var currentStencilFail = gl.getParameter(gl.STENCIL_FAIL);
286         var currentStencilPassDepthFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL);
287         var currentStencilPassDepthPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS);
288 
289         // enable stencil use
290         gl.enable(gl.STENCIL_TEST);
291         // check for OpenGL error while enabling stencil test
292         //cc.CHECK_GL_ERROR_DEBUG();
293 
294         // all bits on the stencil buffer are readonly, except the current layer bit,
295         // this means that operation like glClear or glStencilOp will be masked with this value
296         gl.stencilMask(mask_layer);
297 
298         // manually save the depth test state
299         //GLboolean currentDepthTestEnabled = GL_TRUE;
300         //currentDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST);
301         var currentDepthWriteMask = gl.getParameter(gl.DEPTH_WRITEMASK);
302 
303         // disable depth test while drawing the stencil
304         //glDisable(GL_DEPTH_TEST);
305         // disable update to the depth buffer while drawing the stencil,
306         // as the stencil is not meant to be rendered in the real scene,
307         // it should never prevent something else to be drawn,
308         // only disabling depth buffer update should do
309         gl.depthMask(false);
310 
311         ///////////////////////////////////
312         // CLEAR STENCIL BUFFER
313 
314         // manually clear the stencil buffer by drawing a fullscreen rectangle on it
315         // setup the stencil test func like this:
316         // for each pixel in the fullscreen rectangle
317         //     never draw it into the frame buffer
318         //     if not in inverted mode: set the current layer value to 0 in the stencil buffer
319         //     if in inverted mode: set the current layer value to 1 in the stencil buffer
320         gl.stencilFunc(gl.NEVER, mask_layer, mask_layer);
321         gl.stencilOp(gl.ZERO, gl.KEEP, gl.KEEP);
322 
323         // draw a fullscreen solid rectangle to clear the stencil buffer
324         //ccDrawSolidRect(CCPointZero, ccpFromSize([[CCDirector sharedDirector] winSize]), ccc4f(1, 1, 1, 1));
325         cc.drawingUtil.drawSolidRect(cc.PointZero(), cc.pFromSize(cc.Director.getInstance().getWinSize()), cc.c4f(1, 1, 1, 1));
326 
327         ///////////////////////////////////
328         // DRAW CLIPPING STENCIL
329 
330         // setup the stencil test func like this:
331         // for each pixel in the stencil node
332         //     never draw it into the frame buffer
333         //     if not in inverted mode: set the current layer value to 1 in the stencil buffer
334         //     if in inverted mode: set the current layer value to 0 in the stencil buffer
335         gl.stencilFunc(gl.NEVER, mask_layer, mask_layer);
336         gl.stencilOp(gl.REPLACE, gl.KEEP, gl.KEEP);
337 
338 
339         // draw the stencil node as if it was one of our child
340         // (according to the stencil test func/op and alpha (or alpha shader) test)
341         cc.kmGLPushMatrix();
342         this.transform();
343         this._clippingStencil.visit();
344         cc.kmGLPopMatrix();
345 
346         // restore alpha test state
347         //if (this._alphaThreshold < 1) {
348         // XXX: we need to find a way to restore the shaders of the stencil node and its childs
349         //}
350 
351         // restore the depth test state
352         gl.depthMask(currentDepthWriteMask);
353         //if (currentDepthTestEnabled) {
354         //    glEnable(GL_DEPTH_TEST);
355         //}
356 
357         ///////////////////////////////////
358         // DRAW CONTENT
359 
360         // setup the stencil test func like this:
361         // for each pixel of this node and its childs
362         //     if all layers less than or equals to the current are set to 1 in the stencil buffer
363         //         draw the pixel and keep the current layer in the stencil buffer
364         //     else
365         //         do not draw the pixel but keep the current layer in the stencil buffer
366         gl.stencilFunc(gl.EQUAL, mask_layer_le, mask_layer_le);
367         gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
368 
369         // draw (according to the stencil test func) this node and its childs
370         cc.Node.prototype.visit.call(this, ctx);
371 
372         ///////////////////////////////////
373         // CLEANUP
374 
375         // manually restore the stencil state
376         gl.stencilFunc(currentStencilFunc, currentStencilRef, currentStencilValueMask);
377         gl.stencilOp(currentStencilFail, currentStencilPassDepthFail, currentStencilPassDepthPass);
378         gl.stencilMask(currentStencilWriteMask);
379         if (!currentStencilEnabled)
380             gl.disable(gl.STENCIL_TEST);
381 
382         // we are done using this layer, decrement
383         ccs.Layout._layer--;
384     },
385 
386     _stencilClippingVisitForCanvas: function (ctx) {
387         // return fast (draw nothing, or draw everything if in inverted mode) if:
388         // - nil stencil node
389         // - or stencil node invisible:
390         if (!this._clippingStencil || !this._clippingStencil.isVisible()) {
391             return;
392         }
393 
394         // Composition mode, costy but support texture stencil
395         if (this._cangodhelpme() || this._clippingStencil instanceof cc.Sprite) {
396             var context = ctx || cc.renderContext;
397             // Cache the current canvas, for later use (This is a little bit heavy, replace this solution with other walkthrough)
398             var canvas = context.canvas;
399             var locCache = ccs.Layout._getSharedCache();
400             locCache.width = canvas.width;
401             locCache.height = canvas.height;
402             var locCacheCtx = locCache.getContext("2d");
403             locCacheCtx.drawImage(canvas, 0, 0);
404 
405             context.save();
406             // Draw everything first using node visit function
407             cc.Node.prototype.visit.call(this, context);
408 
409             context.globalCompositeOperation = "destination-in";
410 
411             this.transform(context);
412             this._clippingStencil.visit();
413 
414             context.restore();
415 
416             // Redraw the cached canvas, so that the cliped area shows the background etc.
417             context.save();
418             context.setTransform(1, 0, 0, 1, 0, 0);
419             context.globalCompositeOperation = "destination-over";
420             context.drawImage(locCache, 0, 0);
421             context.restore();
422         }
423         // Clip mode, fast, but only support cc.DrawNode
424         else {
425             var context = ctx || cc.renderContext, i, children = this._children, locChild;
426 
427             context.save();
428             this.transform(context);
429             this._clippingStencil.visit(context);
430             context.clip();
431 
432             // Clip mode doesn't support recusive stencil, so once we used a clip stencil,
433             // so if it has ClippingNode as a child, the child must uses composition stencil.
434             this._cangodhelpme(true);
435             var len = children.length;
436             if (len > 0) {
437                 this.sortAllChildren();
438                 // draw children zOrder < 0
439                 for (i = 0; i < len; i++) {
440                     locChild = children[i];
441                     if (locChild._zOrder < 0)
442                         locChild.visit(context);
443                     else
444                         break;
445                 }
446                 this.draw(context);
447                 for (; i < len; i++) {
448                     children[i].visit(context);
449                 }
450             } else
451                 this.draw(context);
452             this._cangodhelpme(false);
453 
454             context.restore();
455         }
456     },
457 
458     _godhelpme:false,
459     _cangodhelpme: function (godhelpme) {
460         if (godhelpme === true || godhelpme === false)
461             cc.ClippingNode.prototype._godhelpme = godhelpme;
462         return cc.ClippingNode.prototype._godhelpme;
463     },
464 
465     scissorClippingVisit : null,
466     _scissorClippingVisitForWebGL: function (ctx) {
467         var clippingRect = this.getClippingRect();
468         var gl = ctx || cc.renderContext;
469         if (this._handleScissor) {
470             gl.enable(gl.SCISSOR_TEST);
471         }
472         cc.EGLView.getInstance().setScissorInPoints(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
473         cc.Node.prototype.visit.call(this);
474         if (this._handleScissor) {
475             gl.disable(gl.SCISSOR_TEST);
476         }
477     },
478 
479     /**
480      * Changes if layout can clip it's content and locChild.
481      * @param {Boolean} able
482      */
483     setClippingEnabled: function (able) {
484         if (able == this._clippingEnabled) {
485             return;
486         }
487         this._clippingEnabled = able;
488         switch (this._clippingType) {
489             case ccs.LayoutClippingType.stencil:
490                 if (able) {
491                     this.setStencilClippingSize(this._size);
492                 }
493                 else {
494                     this._clippingStencil = null;
495                 }
496                 break;
497             default:
498                 break;
499         }
500     },
501 
502     /**
503      * Set clipping type
504      * @param {ccs.LayoutClippingType} type
505      */
506     setClippingType: function (type) {
507         if (type == this._clippingType) {
508             return;
509         }
510         var clippingEnabled = this.isClippingEnabled();
511         this.setClippingEnabled(false);
512         this._clippingType = type;
513         this.setClippingEnabled(clippingEnabled);
514     },
515 
516     /**
517      * Get clipping type
518      * @returns {ccs.LayoutClippingType}
519      */
520     getClippingType : function(){
521         return this._clippingType;
522     },
523 
524     setStencilClippingSize: function (size) {
525         if (this._clippingEnabled && this._clippingType == ccs.LayoutClippingType.stencil) {
526             var rect = [];
527             rect[0] = cc.p(0, 0);
528             rect[1] = cc.p(size.width, 0);
529             rect[2] = cc.p(size.width, size.height);
530             rect[3] = cc.p(0, size.height);
531             var green = cc.c4f(0, 1, 0, 1);
532             this._clippingStencil.clear();
533             this._clippingStencil.drawPoly(rect, 4, green, 0, green);
534         }
535     },
536 
537     rendererVisitCallBack: function () {
538         this.doLayout();
539     },
540 
541     getClippingRect: function () {
542         if (this._clippingRectDirty){
543             this._handleScissor = true;
544             var worldPos = this.convertToWorldSpace(cc.p(0, 0));
545             var t = this.nodeToWorldTransform();
546             var scissorWidth = this._size.width * t.a;
547             var scissorHeight = this._size.height * t.d;
548             var parentClippingRect;
549             var parent = this;
550             var firstClippingParentFounded = false;
551             while (parent) {
552                 parent = parent.getParent();
553                 if (parent && parent instanceof ccs.Layout) {
554                     if (parent.isClippingEnabled()) {
555                         if (!firstClippingParentFounded) {
556                             this._clippingParent = parent;
557                             firstClippingParentFounded = true;
558                         }
559 
560                         if (parent._clippingType == ccs.LayoutClippingType.scissor) {
561                             this._handleScissor = false;
562                             break;
563                         }
564                     }
565                 }
566             }
567 
568             if (this._clippingParent) {
569                 parentClippingRect = this._clippingParent.getClippingRect();
570                 var finalX = worldPos.x - (scissorWidth * this._anchorPoint.x);
571                 var finalY = worldPos.y - (scissorHeight * this._anchorPoint.y);
572                 var finalWidth = scissorWidth;
573                 var finalHeight = scissorHeight;
574 
575                 var leftOffset = worldPos.x - parentClippingRect.x;
576                 if (leftOffset < 0) {
577                     finalX = parentClippingRect.x;
578                     finalWidth += leftOffset;
579                 }
580                 var rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.x + parentClippingRect.width);
581                 if (rightOffset > 0) {
582                     finalWidth -= rightOffset;
583                 }
584                 var topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.y + parentClippingRect.height);
585                 if (topOffset > 0) {
586                     finalHeight -= topOffset;
587                 }
588                 var bottomOffset = worldPos.y - parentClippingRect.y;
589                 if (bottomOffset < 0) {
590                     finalY = parentClippingRect.x;
591                     finalHeight += bottomOffset;
592                 }
593                 if (finalWidth < 0) {
594                     finalWidth = 0;
595                 }
596                 if (finalHeight < 0) {
597                     finalHeight = 0;
598                 }
599                 this._clippingRect.x = finalX;
600                 this._clippingRect.y = finalY;
601                 this._clippingRect.width = finalWidth;
602                 this._clippingRect.height = finalHeight;
603             }
604             else {
605                 this._clippingRect.x = worldPos.x - (scissorWidth * this._anchorPoint.x);
606                 this._clippingRect.y = worldPos.y - (scissorHeight * this._anchorPoint.y);
607                 this._clippingRect.width = scissorWidth;
608                 this._clippingRect.height = scissorHeight;
609             }
610             this._clippingRectDirty = false;
611         }
612         return this._clippingRect;
613     },
614 
615     onSizeChanged: function () {
616         ccs.Widget.prototype.onSizeChanged.call(this);
617         this.setContentSize(this._size);
618         this.setStencilClippingSize(this._size);
619         this._doLayoutDirty = true;
620         this._clippingRectDirty = true;
621 
622         if (this._backGroundImage) {
623             this._backGroundImage.setPosition(this._size.width / 2.0, this._size.height / 2.0);
624             if (this._backGroundScale9Enabled) {
625                 if (this._backGroundImage instanceof cc.Scale9Sprite) {
626                     this._backGroundImage.setPreferredSize(this._size);
627                 }
628             }
629         }
630         if (this._colorRender) {
631             this._colorRender.setContentSize(this._size);
632         }
633         if (this._gradientRender) {
634             this._gradientRender.setContentSize(this._size);
635         }
636     },
637 
638     /**
639      * Sets background image use scale9 renderer.
640      * @param {Boolean} able
641      */
642     setBackGroundImageScale9Enabled: function (able) {
643         if (this._backGroundScale9Enabled == able) {
644             return;
645         }
646         cc.Node.prototype.removeChild.call(this, this._backGroundImage, true);
647         this._backGroundImage = null;
648         this._backGroundScale9Enabled = able;
649         if (this._backGroundScale9Enabled) {
650             this._backGroundImage = cc.Scale9Sprite.create();
651         }
652         else {
653             this._backGroundImage = cc.Sprite.create();
654         }
655         cc.Node.prototype.addChild.call(this, this._backGroundImage, ccs.BACKGROUNDIMAGEZ, -1);
656         this.setBackGroundImage(this._backGroundImageFileName, this._bgImageTexType);
657         this.setBackGroundImageCapInsets(this._backGroundImageCapInsets);
658     },
659 
660     /**
661      * Get background image is use scale9 renderer.
662      * @returns {Boolean}
663      */
664     isBackGroundImageScale9Enabled:function(){
665         return this._backGroundScale9Enabled;
666     },
667 
668     /**
669      * Sets a background image for layout
670      * @param {String} fileName
671      * @param {ccs.TextureResType} texType
672      */
673     setBackGroundImage: function (fileName, texType) {
674         if (!fileName) {
675             return;
676         }
677         texType = texType || ccs.TextureResType.local;
678         if (this._backGroundImage == null) {
679             this.addBackGroundImage();
680         }
681         this._backGroundImageFileName = fileName;
682         this._bgImageTexType = texType;
683         switch (this._bgImageTexType) {
684             case ccs.TextureResType.local:
685                 this._backGroundImage.initWithFile(fileName);
686                 break;
687             case ccs.TextureResType.plist:
688                 this._backGroundImage.initWithSpriteFrameName(fileName);
689                 break;
690             default:
691                 break;
692         }
693         if (this._backGroundScale9Enabled) {
694             this._backGroundImage.setPreferredSize(this._size);
695         }
696 
697         this.updateBackGroundImageRGBA();
698         this._backGroundImageTextureSize = this._backGroundImage.getContentSize();
699         this._backGroundImage.setPosition(this._size.width / 2.0, this._size.height / 2.0);
700     },
701 
702     /**
703      * Sets a background image capinsets for layout, if the background image is a scale9 render.
704      * @param {cc.Rect} capInsets
705      */
706     setBackGroundImageCapInsets: function (capInsets) {
707         this._backGroundImageCapInsets = capInsets;
708         if (this._backGroundScale9Enabled) {
709             this._backGroundImage.setCapInsets(capInsets);
710         }
711     },
712 
713     /**
714      * Get  background image cap insets.
715      * @returns {cc.Rect}
716      */
717     getBackGroundImageCapInsets:function(){
718         return this._backGroundImageCapInsets;
719     },
720 
721     supplyTheLayoutParameterLackToChild: function (locChild) {
722         if (!locChild) {
723             return;
724         }
725         switch (this._layoutType) {
726             case ccs.LayoutType.absolute:
727                 break;
728             case ccs.LayoutType.linearHorizontal:
729             case ccs.LayoutType.linearVertical:
730                 var layoutParameter = locChild.getLayoutParameter(ccs.LayoutParameterType.linear);
731                 if (!layoutParameter) {
732                     locChild.setLayoutParameter(ccs.LinearLayoutParameter.create());
733                 }
734                 break;
735             case ccs.LayoutType.relative:
736                 var layoutParameter = locChild.getLayoutParameter(ccs.LayoutParameterType.relative);
737                 if (!layoutParameter) {
738                     locChild.setLayoutParameter(ccs.RelativeLayoutParameter.create());
739                 }
740                 break;
741             default:
742                 break;
743         }
744     },
745 
746     /**
747      * init background image renderer.
748      */
749     addBackGroundImage: function () {
750         if (this._backGroundScale9Enabled) {
751             this._backGroundImage = cc.Scale9Sprite.create();
752             this._backGroundImage.setPreferredSize(this._size);
753         }
754         else {
755             this._backGroundImage = cc.Sprite.create();
756         }
757         cc.Node.prototype.addChild.call(this, this._backGroundImage, ccs.BACKGROUNDIMAGEZ, -1);
758         this._backGroundImage.setPosition(this._size.width / 2.0, this._size.height / 2.0);
759     },
760 
761     /**
762      * Remove the background image of layout.
763      */
764     removeBackGroundImage: function () {
765         if (!this._backGroundImage) {
766             return;
767         }
768         cc.Node.prototype.removeChild.call(this, this._backGroundImage, true);
769         this._backGroundImage = null;
770         this._backGroundImageFileName = "";
771         this._backGroundImageTextureSize = cc.SizeZero();
772     },
773 
774     /**
775      * Sets Color Type for layout.
776      * @param {ccs.LayoutBackGroundColorType} type
777      */
778     setBackGroundColorType: function (type) {
779         if (this._colorType == type) {
780             return;
781         }
782         switch (this._colorType) {
783             case ccs.LayoutBackGroundColorType.none:
784                 if (this._colorRender) {
785                     cc.Node.prototype.removeChild.call(this, this._colorRender, true);
786                     this._colorRender = null;
787                 }
788                 if (this._gradientRender) {
789                     cc.Node.prototype.removeChild.call(this, this._gradientRender, true);
790                     this._gradientRender = null;
791                 }
792                 break;
793             case ccs.LayoutBackGroundColorType.solid:
794                 if (this._colorRender) {
795                     cc.Node.prototype.removeChild.call(this, this._colorRender, true);
796                     this._colorRender = null;
797                 }
798                 break;
799             case ccs.LayoutBackGroundColorType.gradient:
800                 if (this._gradientRender) {
801                     cc.Node.prototype.removeChild.call(this, this._gradientRender, true);
802                     this._gradientRender = null;
803                 }
804                 break;
805             default:
806                 break;
807         }
808         this._colorType = type;
809         switch (this._colorType) {
810             case ccs.LayoutBackGroundColorType.none:
811                 break;
812             case ccs.LayoutBackGroundColorType.solid:
813                 this._colorRender = cc.LayerColor.create();
814                 this._colorRender.setContentSize(this._size);
815                 this._colorRender.setOpacity(this._opacity);
816                 this._colorRender.setColor(this._color);
817                 cc.Node.prototype.addChild.call(this, this._colorRender, ccs.BACKGROUNDCOLORRENDERERZ, -1);
818                 break;
819             case ccs.LayoutBackGroundColorType.gradient:
820                 this._gradientRender = cc.LayerGradient.create(cc.c4b(255, 0, 0, 255), cc.c4b(0, 255, 0, 255));
821                 this._gradientRender.setContentSize(this._size);
822                 this._gradientRender.setOpacity(this._opacity);
823                 this._gradientRender.setStartColor(this._startColor);
824                 this._gradientRender.setEndColor(this._endColor);
825                 this._gradientRender.setVector(this._alongVector);
826                 cc.Node.prototype.addChild.call(this, this._gradientRender, ccs.BACKGROUNDCOLORRENDERERZ, -1);
827                 break;
828             default:
829                 break;
830         }
831     },
832 
833     /**
834      * Get color type.
835      * @returns {ccs.LayoutBackGroundColorType}
836      */
837     getBackGroundColorType:function(){
838         return this._colorType;
839     },
840 
841     /**
842      * Sets background color for layout, if color type is LAYOUT_COLOR_SOLID
843      * @param {cc.c3b} color
844      * @param {cc.c3b} endColor
845      */
846     setBackGroundColor: function (color, endColor) {
847         if (!endColor) {
848             this._color.r = color.r;
849             this._color.g = color.g;
850             this._color.b = color.b;
851             if (this._colorRender) {
852                 this._colorRender.setColor(color);
853             }
854         } else {
855             this._startColor.r = color.r;
856             this._startColor.g = color.g;
857             this._startColor.b = color.b;
858 
859             if (this._gradientRender) {
860                 this._gradientRender.setStartColor(color);
861             }
862             this._endColor = endColor;
863             if (this._gradientRender) {
864                 this._gradientRender.setEndColor(endColor);
865             }
866         }
867     },
868 
869     /**
870      * Get back ground color
871      * @returns {cc.Color}
872      */
873     getBackGroundColor:function(){
874         return this._color;
875     },
876 
877     /**
878      * Get back ground start color
879      * @returns {cc.Color}
880      */
881     getBackGroundStartColor:function(){
882         return this._startColor;
883     },
884 
885     /**
886      * Get back ground end color
887      * @returns {cc.Color}
888      */
889     getBackGroundEndColor:function(){
890         return this._endColor;
891     },
892 
893     /**
894      * Sets background opacity layout.
895      * @param {number} opacity
896      */
897     setBackGroundColorOpacity: function (opacity) {
898         this._opacity = opacity;
899         switch (this._colorType) {
900             case ccs.LayoutBackGroundColorType.none:
901                 break;
902             case ccs.LayoutBackGroundColorType.solid:
903                 this._colorRender.setOpacity(opacity);
904                 break;
905             case ccs.LayoutBackGroundColorType.gradient:
906                 this._gradientRender.setOpacity(opacity);
907                 break;
908             default:
909                 break;
910         }
911     },
912 
913     /**
914      * Get background opacity value.
915      * @returns {Number}
916      */
917     getBackGroundColorOpacity:function(){
918         return this._opacity;
919     },
920 
921     /**
922      * Sets background color vector for layout, if color type is LAYOUT_COLOR_GRADIENT
923      * @param {cc.Point} vector
924      */
925     setBackGroundColorVector: function (vector) {
926         this._alongVector.x = vector.x;
927         this._alongVector.y = vector.y;
928         if (this._gradientRender) {
929             this._gradientRender.setVector(vector);
930         }
931     },
932 
933     /**
934      *  Get background color value.
935      * @returns {cc.Point}
936      */
937     getBackGroundColorVector:function(){
938         return this._alongVector;
939     },
940 
941     /**
942      * Set backGround image color
943      * @param {cc.Color3B} color
944      */
945     setBackGroundImageColor: function (color) {
946         this._backGroundImageColor.r = color.r;
947         this._backGroundImageColor.g = color.g;
948         this._backGroundImageColor.b = color.b;
949 
950         this.updateBackGroundImageColor();
951     },
952 
953     /**
954      * Get backGround image color
955      * @param {Number} opacity
956      */
957     setBackGroundImageOpacity: function (opacity) {
958         this._backGroundImageOpacity = opacity;
959         this.getBackGroundImageColor();
960     },
961 
962     /**
963      * Get backGround image color
964      * @returns {cc.Color3B}
965      */
966     getBackGroundImageColor: function () {
967         var color = this._backGroundImageColor;
968         return cc.color(color.r, color.g, color.b);
969     },
970 
971     /**
972      * Get backGround image opacity
973      * @returns {Number}
974      */
975     getBackGroundImageOpacity: function () {
976         return this._backGroundImageOpacity;
977     },
978 
979     updateBackGroundImageColor: function () {
980         this._backGroundImage.setColor(this._backGroundImageColor);
981     },
982 
983     updateBackGroundImageOpacity: function () {
984         this._backGroundImage.setOpacity(this._backGroundImageOpacity);
985     },
986 
987     updateBackGroundImageRGBA: function () {
988         this.updateBackGroundImageColor();
989         this.updateBackGroundImageOpacity();
990     },
991 
992     /**
993      * Gets background image texture size.
994      * @returns {cc.Size}
995      */
996     getBackGroundImageTextureSize: function () {
997         return this._backGroundImageTextureSize;
998     },
999 
1000     /**
1001      * Sets LayoutType.
1002      * @param {ccs.LayoutType} type
1003      */
1004     setLayoutType: function (type) {
1005         this._layoutType = type;
1006         var layoutChildrenArray = this._widgetChildren;
1007         var locChild = null;
1008         for (var i = 0; i < layoutChildrenArray.length; i++) {
1009             locChild = layoutChildrenArray[i];
1010             this.supplyTheLayoutParameterLackToChild(locChild);
1011         }
1012         this._doLayoutDirty = true;
1013     },
1014 
1015     /**
1016      * Gets LayoutType.
1017      * @returns {null}
1018      */
1019     getLayoutType: function () {
1020         return this._layoutType;
1021     },
1022 
1023     /**
1024      * request do layout
1025      */
1026     requestDoLayout: function () {
1027         this._doLayoutDirty = true;
1028     },
1029 
1030     doLayout_LINEAR_VERTICAL: function () {
1031         var layoutChildrenArray = this._widgetChildren;
1032         var layoutSize = this.getSize();
1033         var topBoundary = layoutSize.height;
1034         for (var i = 0; i < layoutChildrenArray.length; ++i) {
1035             var locChild = layoutChildrenArray[i];
1036             var locLayoutParameter = locChild.getLayoutParameter(ccs.LayoutParameterType.linear);
1037 
1038             if (locLayoutParameter) {
1039                 var locChildGravity = locLayoutParameter.getGravity();
1040                 var locAP = locChild.getAnchorPoint();
1041                 var locSize = locChild.getSize();
1042                 var locFinalPosX = locAP.x * locSize.width;
1043                 var locFinalPosY = topBoundary - ((1 - locAP.y) * locSize.height);
1044                 switch (locChildGravity) {
1045                     case ccs.LinearGravity.none:
1046                     case ccs.LinearGravity.left:
1047                         break;
1048                     case ccs.LinearGravity.right:
1049                         locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width);
1050                         break;
1051                     case ccs.LinearGravity.centerHorizontal:
1052                         locFinalPosX = layoutSize.width / 2 - locSize.width * (0.5 - locAP.x);
1053                         break;
1054                     default:
1055                         break;
1056                 }
1057                 var locMargin = locLayoutParameter.getMargin();
1058                 locFinalPosX += locMargin.left;
1059                 locFinalPosY -= locMargin.top;
1060                 locChild.setPosition(cc.p(locFinalPosX, locFinalPosY));
1061                 topBoundary = locChild.getBottomInParent() - locMargin.bottom;
1062             }
1063         }
1064     },
1065     doLayout_LINEAR_HORIZONTAL: function () {
1066         var layoutChildrenArray = this._widgetChildren;
1067         var layoutSize = this.getSize();
1068         var leftBoundary = 0;
1069         for (var i = 0; i < layoutChildrenArray.length; ++i) {
1070             var locChild = layoutChildrenArray[i];
1071             var locLayoutParameter = locChild.getLayoutParameter(ccs.LayoutParameterType.linear);
1072 
1073             if (locLayoutParameter) {
1074                 var locChildGravity = locLayoutParameter.getGravity();
1075                 var locAP = locChild.getAnchorPoint();
1076                 var locSize = locChild.getSize();
1077                 var locFinalPosX = leftBoundary + (locAP.x * locSize.width);
1078                 var locFinalPosY = layoutSize.height - (1 - locAP.y) * locSize.height;
1079                 switch (locChildGravity) {
1080                     case ccs.LinearGravity.none:
1081                     case ccs.LinearGravity.top:
1082                         break;
1083                     case ccs.LinearGravity.bottom:
1084                         locFinalPosY = locAP.y * locSize.height;
1085                         break;
1086                     case ccs.LinearGravity.centerVertical:
1087                         locFinalPosY = layoutSize.height / 2 - locSize.height * (0.5 - locAP.y);
1088                         break;
1089                     default:
1090                         break;
1091                 }
1092                 var locMargin = locLayoutParameter.getMargin();
1093                 locFinalPosX += locMargin.left;
1094                 locFinalPosY -= locMargin.top;
1095                 locChild.setPosition(cc.p(locFinalPosX, locFinalPosY));
1096                 leftBoundary = locChild.getRightInParent() + locMargin.right;
1097             }
1098         }
1099     },
1100     doLayout_RELATIVE: function () {
1101         var layoutChildrenArray = this._widgetChildren;
1102         var length = layoutChildrenArray.length;
1103         var unlayoutChildCount = length;
1104         var layoutSize = this.getSize();
1105 
1106         for (var i = 0; i < length; i++) {
1107             var locChild = layoutChildrenArray[i];
1108             var locLayoutParameter = locChild.getLayoutParameter(ccs.LayoutParameterType.relative);
1109             locLayoutParameter._put = false;
1110         }
1111 
1112         while (unlayoutChildCount > 0) {
1113             for (var i = 0; i < length; i++) {
1114                 var locChild = layoutChildrenArray[i];
1115                 var locLayoutParameter = locChild.getLayoutParameter(ccs.LayoutParameterType.relative);
1116 
1117                 if (locLayoutParameter) {
1118                     if (locLayoutParameter._put) {
1119                         continue;
1120                     }
1121                     var locAP = locChild.getAnchorPoint();
1122                     var locSize = locChild.getSize();
1123                     var locAlign = locLayoutParameter.getAlign();
1124                     var locRelativeName = locLayoutParameter.getRelativeToWidgetName();
1125                     var locRelativeWidget = null;
1126                     var locRelativeWidgetLP = null;
1127                     var locFinalPosX = 0;
1128                     var locFinalPosY = 0;
1129                     if (locRelativeName) {
1130                         locRelativeWidget = ccs.UIHelper.seekWidgetByRelativeName(this, locRelativeName);
1131                         if (locRelativeWidget) {
1132                             locRelativeWidgetLP = locRelativeWidget.getLayoutParameter(ccs.LayoutParameterType.relative);
1133                         }
1134                     }
1135                     switch (locAlign) {
1136                         case ccs.RelativeAlign.alignNone:
1137                         case ccs.RelativeAlign.alignParentTopLeft:
1138                             locFinalPosX = locAP.x * locSize.width;
1139                             locFinalPosY = layoutSize.height - ((1 - locAP.y) * locSize.height);
1140                             break;
1141                         case ccs.RelativeAlign.alignParentTopCenterHorizontal:
1142                             locFinalPosX = layoutSize.width * 0.5 - locSize.width * (0.5 - locAP.x);
1143                             locFinalPosY = layoutSize.height - ((1 - locAP.y) * locSize.height);
1144                             break;
1145                         case ccs.RelativeAlign.alignParentTopRight:
1146                             locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width);
1147                             locFinalPosY = layoutSize.height - ((1 - locAP.y) * locSize.height);
1148                             break;
1149                         case ccs.RelativeAlign.alignParentLeftCenterVertical:
1150                             locFinalPosX = locAP.x * locSize.width;
1151                             locFinalPosY = layoutSize.height * 0.5 - locSize.height * (0.5 - locAP.y);
1152                             break;
1153                         case ccs.RelativeAlign.centerInParent:
1154                             locFinalPosX = layoutSize.width * 0.5 - locSize.width * (0.5 - locAP.x);
1155                             locFinalPosY = layoutSize.height * 0.5 - locSize.height * (0.5 - locAP.y);
1156                             break;
1157                         case ccs.RelativeAlign.alignParentRightCenterVertical:
1158                             locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width);
1159                             locFinalPosY = layoutSize.height * 0.5 - locSize.height * (0.5 - locAP.y);
1160                             break;
1161                         case ccs.RelativeAlign.alignParentLeftBottom:
1162                             locFinalPosX = locAP.x * locSize.width;
1163                             locFinalPosY = locAP.y * locSize.height;
1164                             break;
1165                         case ccs.RelativeAlign.alignParentBottomCenterHorizontal:
1166                             locFinalPosX = layoutSize.width * 0.5 - locSize.width * (0.5 - locAP.x);
1167                             locFinalPosY = locAP.y * locSize.height;
1168                             break;
1169                         case ccs.RelativeAlign.alignParentRightBottom:
1170                             locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width);
1171                             locFinalPosY = locAP.y * locSize.height;
1172                             break;
1173 
1174                         case ccs.RelativeAlign.locationAboveLeftAlign:
1175                             if (locRelativeWidget) {
1176                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1177                                     continue;
1178                                 }
1179                                 var locationBottom = locRelativeWidget.getTopInParent();
1180                                 var locationLeft = locRelativeWidget.getLeftInParent();
1181                                 locFinalPosY = locationBottom + locAP.y * locSize.height;
1182                                 locFinalPosX = locationLeft + locAP.x * locSize.width;
1183                             }
1184                             break;
1185                         case ccs.RelativeAlign.locationAboveCenter:
1186                             if (locRelativeWidget) {
1187                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1188                                     continue;
1189                                 }
1190                                 var rbs = locRelativeWidget.getSize();
1191                                 var locationBottom = locRelativeWidget.getTopInParent();
1192 
1193                                 locFinalPosY = locationBottom + locAP.y * locSize.height;
1194                                 locFinalPosX = locRelativeWidget.getLeftInParent() + rbs.width * 0.5 + locAP.x * locSize.width - locSize.width * 0.5;
1195                             }
1196                             break;
1197                         case ccs.RelativeAlign.locationAboveRightAlign:
1198                             if (locRelativeWidget) {
1199                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1200                                     continue;
1201                                 }
1202                                 var locationBottom = locRelativeWidget.getTopInParent();
1203                                 var locationRight = locRelativeWidget.getRightInParent();
1204                                 locFinalPosY = locationBottom + locAP.y * locSize.height;
1205                                 locFinalPosX = locationRight - (1 - locAP.x) * locSize.width;
1206                             }
1207                             break;
1208                         case ccs.RelativeAlign.locationLeftOfTopAlign:
1209                             if (locRelativeWidget) {
1210                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1211                                     continue;
1212                                 }
1213                                 var locationTop = locRelativeWidget.getTopInParent();
1214                                 var locationRight = locRelativeWidget.getLeftInParent();
1215                                 locFinalPosY = locationTop - (1 - locAP.y) * locSize.height;
1216                                 locFinalPosX = locationRight - (1 - locAP.x) * locSize.width;
1217                             }
1218                             break;
1219                         case ccs.RelativeAlign.locationLeftOfCenter:
1220                             if (locRelativeWidget) {
1221                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1222                                     continue;
1223                                 }
1224                                 var rbs = locRelativeWidget.getSize();
1225                                 var locationRight = locRelativeWidget.getLeftInParent();
1226                                 locFinalPosX = locationRight - (1 - locAP.x) * locSize.width;
1227 
1228                                 locFinalPosY = locRelativeWidget.getBottomInParent() + rbs.height * 0.5 + locAP.y * locSize.height - locSize.height * 0.5;
1229                             }
1230                             break;
1231                         case ccs.RelativeAlign.locationLeftOfBottomAlign:
1232                             if (locRelativeWidget) {
1233                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1234                                     continue;
1235                                 }
1236                                 var locationBottom = locRelativeWidget.getBottomInParent();
1237                                 var locationRight = locRelativeWidget.getLeftInParent();
1238                                 locFinalPosY = locationBottom + locAP.y * locSize.height;
1239                                 locFinalPosX = locationRight - (1 - locAP.x) * locSize.width;
1240                             }
1241                             break;
1242                         case ccs.RelativeAlign.locationRightOfTopAlign:
1243                             if (locRelativeWidget) {
1244                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1245                                     continue;
1246                                 }
1247                                 var locationTop = locRelativeWidget.getTopInParent();
1248                                 var locationLeft = locRelativeWidget.getRightInParent();
1249                                 locFinalPosY = locationTop - (1 - locAP.y) * locSize.height;
1250                                 locFinalPosX = locationLeft + locAP.x * locSize.width;
1251                             }
1252                             break;
1253                         case ccs.RelativeAlign.locationRightOfCenter:
1254                             if (locRelativeWidget) {
1255                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1256                                     continue;
1257                                 }
1258                                 var rbs = locRelativeWidget.getSize();
1259                                 var locationLeft = locRelativeWidget.getRightInParent();
1260                                 locFinalPosX = locationLeft + locAP.x * locSize.width;
1261 
1262                                 locFinalPosY = locRelativeWidget.getBottomInParent() + rbs.height * 0.5 + locAP.y * locSize.height - locSize.height * 0.5;
1263                             }
1264                             break;
1265                         case ccs.RelativeAlign.locationRightOfBottomAlign:
1266                             if (locRelativeWidget) {
1267                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1268                                     continue;
1269                                 }
1270                                 var locationBottom = locRelativeWidget.getBottomInParent();
1271                                 var locationLeft = locRelativeWidget.getRightInParent();
1272                                 locFinalPosY = locationBottom + locAP.y * locSize.height;
1273                                 locFinalPosX = locationLeft + locAP.x * locSize.width;
1274                             }
1275                             break;
1276                         case ccs.RelativeAlign.locationBelowLeftAlign:
1277                             if (locRelativeWidget) {
1278                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1279                                     continue;
1280                                 }
1281                                 var locationTop = locRelativeWidget.getBottomInParent();
1282                                 var locationLeft = locRelativeWidget.getLeftInParent();
1283                                 locFinalPosY = locationTop - (1 - locAP.y) * locSize.height;
1284                                 locFinalPosX = locationLeft + locAP.x * locSize.width;
1285                             }
1286                             break;
1287                         case ccs.RelativeAlign.locationBelowCenter:
1288                             if (locRelativeWidget) {
1289                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1290                                     continue;
1291                                 }
1292                                 var rbs = locRelativeWidget.getSize();
1293                                 var locationTop = locRelativeWidget.getBottomInParent();
1294 
1295                                 locFinalPosY = locationTop - (1 - locAP.y) * locSize.height;
1296                                 locFinalPosX = locRelativeWidget.getLeftInParent() + rbs.width * 0.5 + locAP.x * locSize.width - locSize.width * 0.5;
1297                             }
1298                             break;
1299                         case ccs.RelativeAlign.locationBelowRightAlign:
1300                             if (locRelativeWidget) {
1301                                 if (locRelativeWidgetLP && !locRelativeWidgetLP._put) {
1302                                     continue;
1303                                 }
1304                                 var locationTop = locRelativeWidget.getBottomInParent();
1305                                 var locationRight = locRelativeWidget.getRightInParent();
1306                                 locFinalPosY = locationTop - (1 - locAP.y) * locSize.height;
1307                                 locFinalPosX = locationRight - (1 - locAP.x) * locSize.width;
1308                             }
1309                             break;
1310                         default:
1311                             break;
1312                     }
1313                     var locRelativeWidgetMargin,locRelativeWidgetLPAlign;
1314                     var locMargin = locLayoutParameter.getMargin();
1315                     if (locRelativeWidgetLP) {
1316                         locRelativeWidgetMargin = locRelativeWidgetLP.getMargin();
1317                         locRelativeWidgetLPAlign = locRelativeWidgetLP.getAlign();
1318                     }
1319                     //handle margin
1320                     switch (locAlign) {
1321                         case ccs.RelativeAlign.alignNone:
1322                         case ccs.RelativeAlign.alignParentTopLeft:
1323                             locFinalPosX += locMargin.left;
1324                             locFinalPosY -= locMargin.top;
1325                             break;
1326                         case ccs.RelativeAlign.alignParentTopCenterHorizontal:
1327                             locFinalPosY -= locMargin.top;
1328                             break;
1329                         case ccs.RelativeAlign.alignParentTopRight:
1330                             locFinalPosX -= locMargin.right;
1331                             locFinalPosY -= locMargin.top;
1332                             break;
1333                         case ccs.RelativeAlign.alignParentLeftCenterVertical:
1334                             locFinalPosX += locMargin.left;
1335                             break;
1336                         case ccs.RelativeAlign.centerInParent:
1337                             break;
1338                         case ccs.RelativeAlign.alignParentRightCenterVertical:
1339                             locFinalPosX -= locMargin.right;
1340                             break;
1341                         case ccs.RelativeAlign.alignParentLeftBottom:
1342                             locFinalPosX += locMargin.left;
1343                             locFinalPosY += locMargin.bottom;
1344                             break;
1345                         case ccs.RelativeAlign.alignParentBottomCenterHorizontal:
1346                             locFinalPosY += locMargin.bottom;
1347                             break;
1348                         case ccs.RelativeAlign.alignParentRightBottom:
1349                             locFinalPosX -= locMargin.right;
1350                             locFinalPosY += locMargin.bottom;
1351                             break;
1352 
1353                         case ccs.RelativeAlign.locationAboveLeftAlign:
1354                             locFinalPosY += locMargin.bottom;
1355                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopCenterHorizontal
1356                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopLeft
1357                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignNone
1358                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopRight)
1359                             {
1360                                 locFinalPosY += locRelativeWidgetMargin.top;
1361                             }
1362                             locFinalPosY += locMargin.left;
1363                             break;
1364                         case ccs.RelativeAlign.locationAboveCenter:
1365                             locFinalPosY += locMargin.bottom;
1366                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopCenterHorizontal
1367                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopLeft
1368                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignNone
1369                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopRight)
1370                             {
1371                                 locFinalPosY += locRelativeWidgetMargin.top;
1372                             }
1373                             break;
1374                         case ccs.RelativeAlign.locationAboveRightAlign:
1375                             locFinalPosY += locMargin.bottom;
1376                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopCenterHorizontal
1377                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopLeft
1378                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignNone
1379                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopRight)
1380                             {
1381                                 locFinalPosY += locRelativeWidgetMargin.top;
1382                             }
1383                             locFinalPosX -= locMargin.right;
1384                             break;
1385                         case ccs.RelativeAlign.locationLeftOfTopAlign:
1386                             locFinalPosX -= locMargin.right;
1387                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopLeft
1388                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignNone
1389                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftBottom
1390                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftCenterVertical)
1391                             {
1392                                 locFinalPosX -= locRelativeWidgetMargin.left;
1393                             }
1394                             locFinalPosY -= locMargin.top;
1395                             break;
1396                         case ccs.RelativeAlign.locationLeftOfCenter:
1397                             locFinalPosX -= locMargin.right;
1398                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopLeft
1399                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignNone
1400                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftBottom
1401                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftCenterVertical)
1402                             {
1403                                 locFinalPosX -= locRelativeWidgetMargin.left;
1404                             }
1405                             break;
1406                         case ccs.RelativeAlign.locationLeftOfBottomAlign:
1407                             locFinalPosX -= locMargin.right;
1408                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopLeft
1409                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignNone
1410                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftBottom
1411                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftCenterVertical)
1412                             {
1413                                 locFinalPosX -= locRelativeWidgetMargin.left;
1414                             }
1415                             locFinalPosY += locMargin.bottom;
1416                             break;
1417                             break;
1418                         case ccs.RelativeAlign.locationRightOfTopAlign:
1419                             locFinalPosX += locMargin.left;
1420                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopRight
1421                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightBottom
1422                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightCenterVertical)
1423                             {
1424                                 locFinalPosX += locRelativeWidgetMargin.right;
1425                             }
1426                             locFinalPosY -= locMargin.top;
1427                             break;
1428                         case ccs.RelativeAlign.locationRightOfCenter:
1429                             locFinalPosX += locMargin.left;
1430                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopRight
1431                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightBottom
1432                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightCenterVertical)
1433                             {
1434                                 locFinalPosX += locRelativeWidgetMargin.right;
1435                             }
1436                             break;
1437                         case ccs.RelativeAlign.locationRightOfBottomAlign:
1438                             locFinalPosX += locMargin.left;
1439                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentTopRight
1440                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightBottom
1441                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightCenterVertical)
1442                             {
1443                                 locFinalPosX += locRelativeWidgetMargin.right;
1444                             }
1445                             locFinalPosY += locMargin.bottom;
1446                             break;
1447                             break;
1448                         case ccs.RelativeAlign.locationBelowLeftAlign:
1449                             locFinalPosY -= locMargin.top;
1450                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftBottom
1451                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightBottom
1452                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentBottomCenterHorizontal)
1453                             {
1454                                 locFinalPosY -= locRelativeWidgetMargin.bottom;
1455                             }
1456                             locFinalPosX += locMargin.left;
1457                             break;
1458                         case ccs.RelativeAlign.locationBelowCenter:
1459                             locFinalPosY -= locMargin.top;
1460                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftBottom
1461                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightBottom
1462                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentBottomCenterHorizontal)
1463                             {
1464                                 locFinalPosY -= locRelativeWidgetMargin.bottom;
1465                             }
1466                             break;
1467                         case ccs.RelativeAlign.locationBelowRightAlign:
1468                             locFinalPosY -= locMargin.top;
1469                             if (locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentLeftBottom
1470                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentRightBottom
1471                                 && locRelativeWidgetLPAlign != ccs.RelativeAlign.alignParentBottomCenterHorizontal)
1472                             {
1473                                 locFinalPosY -= locRelativeWidgetMargin.bottom;
1474                             }
1475                             locFinalPosX -= locMargin.right;
1476                             break;
1477                         default:
1478                             break;
1479                     }
1480                     locChild.setPosition(cc.p(locFinalPosX, locFinalPosY));
1481                     locLayoutParameter._put = true;
1482                     unlayoutChildCount--;
1483                 }
1484             }
1485         }
1486     },
1487     doLayout: function () {
1488         if(!this._doLayoutDirty){
1489             return;
1490         }
1491         switch (this._layoutType) {
1492             case ccs.LayoutType.absolute:
1493                 break;
1494             case ccs.LayoutType.linearVertical:
1495                 this.doLayout_LINEAR_VERTICAL();
1496                 break;
1497             case ccs.LayoutType.linearHorizontal:
1498                 this.doLayout_LINEAR_HORIZONTAL();
1499                 break;
1500             case ccs.LayoutType.relative:
1501                 this.doLayout_RELATIVE();
1502                 break;
1503             default:
1504                 break;
1505         }
1506         this._doLayoutDirty = false;
1507     },
1508 
1509     /**
1510      * Returns the "class name" of widget.
1511      * @returns {string}
1512      */
1513     getDescription: function () {
1514         return "Layout";
1515     },
1516 
1517     createCloneInstance: function () {
1518         return ccs.Layout.create();
1519     },
1520 
1521     copyClonedWidgetChildren: function (model) {
1522         ccs.Widget.prototype.copyClonedWidgetChildren.call(this, model);
1523     },
1524 
1525     copySpecialProperties: function (layout) {
1526         this.setBackGroundImageScale9Enabled(layout._backGroundScale9Enabled);
1527         this.setBackGroundImage(layout._backGroundImageFileName, layout._bgImageTexType);
1528         this.setBackGroundImageCapInsets(layout._backGroundImageCapInsets);
1529         this.setBackGroundColorType(layout._colorType);
1530         this.setBackGroundColor(layout._color);
1531         this.setBackGroundColor(layout._startColor, layout._endColor);
1532         this.setBackGroundColorOpacity(layout._opacity);
1533         this.setBackGroundColorVector(layout._alongVector);
1534         this.setLayoutType(layout._layoutType);
1535         this.setClippingEnabled(layout._clippingEnabled);
1536         this.setClippingType(layout._clippingType);
1537     }
1538 });
1539 ccs.Layout._init_once = null;
1540 ccs.Layout._visit_once = null;
1541 ccs.Layout._layer = null;
1542 ccs.Layout._sharedCache = null;
1543 
1544 if (cc.Browser.supportWebGL) {
1545     //WebGL
1546     ccs.Layout.prototype.initStencil = ccs.Layout.prototype._initStencilForWebGL;
1547     ccs.Layout.prototype.stencilClippingVisit = ccs.Layout.prototype._stencilClippingVisitForWebGL;
1548     ccs.Layout.prototype.scissorClippingVisit = ccs.Layout.prototype._scissorClippingVisitForWebGL;
1549 }else{
1550     ccs.Layout.prototype.initStencil = ccs.Layout.prototype._initStencilForCanvas;
1551     ccs.Layout.prototype.stencilClippingVisit = ccs.Layout.prototype._stencilClippingVisitForCanvas;
1552     ccs.Layout.prototype.scissorClippingVisit = ccs.Layout.prototype._stencilClippingVisitForCanvas;
1553 }
1554 ccs.Layout._getSharedCache = function () {
1555     return (cc.ClippingNode._sharedCache) || (cc.ClippingNode._sharedCache = document.createElement("canvas"));
1556 };
1557 /**
1558  * allocates and initializes a UILayout.
1559  * @constructs
1560  * @return {ccs.Layout}
1561  * @example
1562  * // example
1563  * var uiLayout = ccs.Layout.create();
1564  */
1565 ccs.Layout.create = function () {
1566     var layout = new ccs.Layout();
1567     if (layout && layout.init()) {
1568         return layout;
1569     }
1570     return null;
1571 };
1572