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;