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