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