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;