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