1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2012 Neofect. All rights reserved. 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 Created by Jung Sang-Taik on 2012-03-16 26 ****************************************************************************/ 27 28 cc.POSITIONS_CENTRE = 0; 29 cc.POSITIONS_TOP = 1; 30 cc.POSITIONS_LEFT = 2; 31 cc.POSITIONS_RIGHT = 3; 32 cc.POSITIONS_BOTTOM = 4; 33 cc.POSITIONS_TOPRIGHT = 5; 34 cc.POSITIONS_TOPLEFT = 6; 35 cc.POSITIONS_BOTTOMRIGHT = 7; 36 cc.POSITIONS_BOTTOMLEFT = 8; 37 38 /** 39 * A 9-slice sprite for cocos2d. 40 * 41 * 9-slice scaling allows you to specify how scaling is applied 42 * to specific areas of a sprite. With 9-slice scaling (3x3 grid), 43 * you can ensure that the sprite does not become distorted when 44 * scaled. 45 * 46 * @see http://yannickloriot.com/library/ios/cccontrolextension/Classes/CCScale9Sprite.html 47 * @class 48 * @extends cc.Sprite 49 */ 50 cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ 51 RGBAProtocol: true, 52 53 _spriteRect: null, 54 _capInsetsInternal: null, 55 _positionsAreDirty: false, 56 57 _scale9Image: null, 58 _topLeft: null, 59 _top: null, 60 _topRight: null, 61 _left: null, 62 _centre: null, 63 _right: null, 64 _bottomLeft: null, 65 _bottom: null, 66 _bottomRight: null, 67 68 _colorUnmodified: null, 69 _opacityModifyRGB: false, 70 71 _originalSize: null, 72 _preferredSize: null, 73 _opacity: 0, 74 _color: null, 75 _capInsets: null, 76 _insetLeft: 0, 77 _insetTop: 0, 78 _insetRight: 0, 79 _insetBottom: 0, 80 81 _spritesGenerated: false, 82 _spriteFrameRotated: false, 83 _textureLoaded:false, 84 _loadedEventListeners: null, 85 86 /** 87 * return texture is loaded 88 * @returns {boolean} 89 */ 90 textureLoaded:function(){ 91 return this._textureLoaded; 92 }, 93 94 /** 95 * add texture loaded event listener 96 * @param {Function} callback 97 * @param {Object} target 98 */ 99 addLoadedEventListener:function(callback, target){ 100 this._loadedEventListeners.push({eventCallback:callback, eventTarget:target}); 101 }, 102 103 _callLoadedEventCallbacks:function(){ 104 this._textureLoaded = true; 105 var locListeners = this._loadedEventListeners; 106 for(var i = 0, len = locListeners.length; i < len; i++){ 107 var selCallback = locListeners[i]; 108 selCallback.eventCallback.call(selCallback.eventTarget, this); 109 } 110 locListeners.length = 0; 111 }, 112 113 _updateCapInset: function () { 114 var insets, locInsetLeft = this._insetLeft, locInsetTop = this._insetTop, locInsetRight = this._insetRight; 115 var locSpriteRect = this._spriteRect, locInsetBottom = this._insetBottom; 116 if (locInsetLeft === 0 && locInsetTop === 0 && locInsetRight === 0 && locInsetBottom === 0) { 117 insets = cc.RectZero(); 118 } else { 119 insets = this._spriteFrameRotated ? cc.rect(locInsetBottom, locInsetLeft, 120 locSpriteRect.width - locInsetRight - locInsetLeft, 121 locSpriteRect.height - locInsetTop - locInsetBottom) : 122 cc.rect(locInsetLeft, locInsetTop, 123 locSpriteRect.width - locInsetLeft - locInsetRight, 124 locSpriteRect.height - locInsetTop - locInsetBottom); 125 } 126 this.setCapInsets(insets); 127 }, 128 129 _updatePositions: function () { 130 // Check that instances are non-NULL 131 if (!((this._topLeft) && (this._topRight) && (this._bottomRight) && 132 (this._bottomLeft) && (this._centre))) { 133 // if any of the above sprites are NULL, return 134 return; 135 } 136 137 var size = this._contentSize; 138 var locTopLeft = this._topLeft, locTopRight = this._topRight, locBottomRight = this._bottomRight, locBottomLeft = this._bottomLeft; 139 var locCenter = this._centre, locCenterContentSize = this._centre.getContentSize(); 140 var locTopLeftContentSize = locTopLeft.getContentSize(); 141 var locBottomLeftContentSize = locBottomLeft.getContentSize(); 142 143 var sizableWidth = size._width - locTopLeftContentSize.width - locTopRight.getContentSize().width; 144 var sizableHeight = size._height - locTopLeftContentSize.height - locBottomRight.getContentSize().height; 145 var horizontalScale = sizableWidth / locCenterContentSize.width; 146 var verticalScale = sizableHeight / locCenterContentSize.height; 147 var rescaledWidth = locCenterContentSize.width * horizontalScale; 148 var rescaledHeight = locCenterContentSize.height * verticalScale; 149 150 var leftWidth = locBottomLeftContentSize.width; 151 var bottomHeight = locBottomLeftContentSize.height; 152 153 if(!cc.Browser.supportWebGL) { 154 //browser is in canvas mode, need to manually control rounding to prevent overlapping pixels 155 var roundedRescaledWidth = Math.round(rescaledWidth); 156 if(rescaledWidth != roundedRescaledWidth) { 157 rescaledWidth = roundedRescaledWidth; 158 horizontalScale = rescaledWidth/locCenterContentSize.width; 159 } 160 var roundedRescaledHeight = Math.round(rescaledHeight); 161 if(rescaledHeight != roundedRescaledHeight) { 162 rescaledHeight = roundedRescaledHeight; 163 verticalScale = rescaledHeight/locCenterContentSize.height; 164 } 165 } 166 locCenter.setScaleX(horizontalScale); 167 locCenter.setScaleY(verticalScale); 168 169 var locLeft = this._left, locRight = this._right, locTop = this._top, locBottom = this._bottom; 170 var tempAP = cc.p(0, 0); 171 locBottomLeft.setAnchorPoint(tempAP); 172 locBottomRight.setAnchorPoint(tempAP); 173 locTopLeft.setAnchorPoint(tempAP); 174 locTopRight.setAnchorPoint(tempAP); 175 locLeft.setAnchorPoint(tempAP); 176 locRight.setAnchorPoint(tempAP); 177 locTop.setAnchorPoint(tempAP); 178 locBottom.setAnchorPoint(tempAP); 179 locCenter.setAnchorPoint(tempAP); 180 181 // Position corners 182 locBottomLeft.setPosition(0, 0); 183 locBottomRight.setPosition(leftWidth + rescaledWidth, 0); 184 locTopLeft.setPosition(0, bottomHeight + rescaledHeight); 185 locTopRight.setPosition(leftWidth + rescaledWidth, bottomHeight + rescaledHeight); 186 187 // Scale and position borders 188 locLeft.setPosition(0, bottomHeight); 189 locLeft.setScaleY(verticalScale); 190 locRight.setPosition(leftWidth + rescaledWidth, bottomHeight); 191 locRight.setScaleY(verticalScale); 192 locBottom.setPosition(leftWidth, 0); 193 locBottom.setScaleX(horizontalScale); 194 locTop.setPosition(leftWidth, bottomHeight + rescaledHeight); 195 locTop.setScaleX(horizontalScale); 196 197 // Position centre 198 locCenter.setPosition(leftWidth, bottomHeight); 199 }, 200 201 ctor: function () { 202 cc.NodeRGBA.prototype.ctor.call(this); 203 this._spriteRect = cc.RectZero(); 204 this._capInsetsInternal = cc.RectZero(); 205 206 this._colorUnmodified = cc.white(); 207 this._originalSize = new cc.Size(0, 0); 208 this._preferredSize = new cc.Size(0, 0); 209 this._color = cc.white(); 210 this._opacity = 255; 211 this._capInsets = cc.RectZero(); 212 this._loadedEventListeners = []; 213 }, 214 215 /** Original sprite's size. */ 216 getOriginalSize: function () { 217 return this._originalSize; 218 }, 219 220 //if the preferredSize component is given as -1, it is ignored 221 getPreferredSize: function () { 222 return this._preferredSize; 223 }, 224 setPreferredSize: function (preferredSize) { 225 this.setContentSize(preferredSize); 226 this._preferredSize = preferredSize; 227 }, 228 229 /** Opacity: conforms to CCRGBAProtocol protocol */ 230 getOpacity: function () { 231 return this._opacity; 232 }, 233 setOpacity: function (opacity) { 234 if(!this._scale9Image){ 235 return; 236 } 237 this._opacity = opacity; 238 var scaleChildren = this._scale9Image.getChildren(); 239 for (var i = 0; i < scaleChildren.length; i++) { 240 var selChild = scaleChildren[i]; 241 if (selChild && selChild.RGBAProtocol) 242 selChild.setOpacity(opacity); 243 } 244 }, 245 246 /** Color: conforms to CCRGBAProtocol protocol */ 247 getColor: function () { 248 return this._color; 249 }, 250 setColor: function (color) { 251 if(!this._scale9Image){ 252 return; 253 } 254 this._color = color; 255 var scaleChildren = this._scale9Image.getChildren(); 256 for (var i = 0; i < scaleChildren.length; i++) { 257 var selChild = scaleChildren[i]; 258 if (selChild && selChild.RGBAProtocol) 259 selChild.setColor(color); 260 } 261 }, 262 263 getCapInsets: function () { 264 return this._capInsets; 265 }, 266 267 setCapInsets: function (capInsets) { 268 if(!this._scale9Image){ 269 return; 270 } 271 //backup the contentSize 272 var contentSize = this._contentSize; 273 var tempWidth = contentSize._width, tempHeight = contentSize._height; 274 275 this.updateWithBatchNode(this._scale9Image, this._spriteRect, this._spriteFrameRotated, capInsets); 276 //restore the contentSize 277 this.setContentSize(tempWidth, tempHeight); 278 }, 279 280 /** 281 * Gets the left side inset 282 * @returns {number} 283 */ 284 getInsetLeft: function () { 285 return this._insetLeft; 286 }, 287 288 /** 289 * Sets the left side inset 290 * @param {Number} insetLeft 291 */ 292 setInsetLeft: function (insetLeft) { 293 this._insetLeft = insetLeft; 294 this._updateCapInset(); 295 }, 296 297 /** 298 * Gets the top side inset 299 * @returns {number} 300 */ 301 getInsetTop: function () { 302 return this._insetTop; 303 }, 304 305 /** 306 * Sets the top side inset 307 * @param {Number} insetTop 308 */ 309 setInsetTop: function (insetTop) { 310 this._insetTop = insetTop; 311 this._updateCapInset(); 312 }, 313 314 /** 315 * Gets the right side inset 316 * @returns {number} 317 */ 318 getInsetRight: function () { 319 return this._insetRight; 320 }, 321 /** 322 * Sets the right side inset 323 * @param {Number} insetRight 324 */ 325 setInsetRight: function (insetRight) { 326 this._insetRight = insetRight; 327 this._updateCapInset(); 328 }, 329 330 /** 331 * Gets the bottom side inset 332 * @returns {number} 333 */ 334 getInsetBottom: function () { 335 return this._insetBottom; 336 }, 337 /** 338 * Sets the bottom side inset 339 * @param {number} insetBottom 340 */ 341 setInsetBottom: function (insetBottom) { 342 this._insetBottom = insetBottom; 343 this._updateCapInset(); 344 }, 345 346 /** 347 * Sets the untransformed size of the Scale9Sprite. 348 * @override 349 * @param {cc.Size|Number} size The untransformed size of the Scale9Sprite or The untransformed size's width of the Scale9Sprite. 350 * @param {Number} [height] The untransformed size's height of the Scale9Sprite. 351 */ 352 setContentSize: function (size, height) { 353 if(arguments.length === 2) 354 cc.Node.prototype.setContentSize.call(this, size, height); 355 else 356 cc.Node.prototype.setContentSize.call(this, size); 357 this._positionsAreDirty = true; 358 }, 359 360 visit: function (ctx) { 361 if (this._positionsAreDirty) { 362 this._updatePositions(); 363 this._positionsAreDirty = false; 364 } 365 cc.NodeRGBA.prototype.visit.call(this, ctx); 366 }, 367 368 init: function () { 369 return this.initWithBatchNode(null, cc.RectZero(), false, cc.RectZero()); 370 }, 371 372 initWithBatchNode: function (batchNode, rect, rotated, capInsets) { 373 if (arguments.length === 3) { 374 capInsets = rotated; 375 rotated = false; 376 } 377 378 if (batchNode) { 379 this.updateWithBatchNode(batchNode, rect, rotated, capInsets); 380 } 381 this.setAnchorPoint(0.5, 0.5); 382 this._positionsAreDirty = true; 383 return true; 384 }, 385 386 /** 387 * Initializes a 9-slice sprite with a texture file, a delimitation zone and 388 * with the specified cap insets. 389 * Once the sprite is created, you can then call its "setContentSize:" method 390 * to resize the sprite will all it's 9-slice goodness intact. 391 * It respects the anchorPoint too. 392 * 393 * @param file The name of the texture file. 394 * @param rect The rectangle that describes the sub-part of the texture that 395 * is the whole image. If the shape is the whole texture, set this to the 396 * texture's full rect. 397 * @param capInsets The values to use for the cap insets. 398 */ 399 initWithFile: function (file, rect, capInsets) { 400 if (file instanceof cc.Rect) { 401 file = arguments[1]; 402 capInsets = arguments[0]; 403 rect = cc.RectZero(); 404 } else { 405 rect = rect || cc.RectZero(); 406 capInsets = capInsets || cc.RectZero(); 407 } 408 409 if(!file) 410 throw "cc.Scale9Sprite.initWithFile(): file should be non-null"; 411 412 var texture = cc.TextureCache.getInstance().textureForKey(file); 413 if (!texture) { 414 texture = cc.TextureCache.getInstance().addImage(file); 415 var locLoaded = texture.isLoaded(); 416 this._textureLoaded = locLoaded; 417 if(!locLoaded){ 418 texture.addLoadedEventListener(function(sender){ 419 // the texture is rotated on Canvas render mode, so isRotated always is false. 420 var preferredSize = this._preferredSize; 421 preferredSize = cc.size(preferredSize.width, preferredSize.height); 422 var size = sender.getContentSize(); 423 this.updateWithBatchNode(this._scale9Image, cc.rect(0,0,size.width,size.height), false, this._capInsets); 424 this.setPreferredSize(preferredSize); 425 this._positionsAreDirty = true; 426 this._callLoadedEventCallbacks(); 427 }, this); 428 } 429 } 430 var batchnode = cc.SpriteBatchNode.create(file, 9); 431 return this.initWithBatchNode(batchnode, rect, false, capInsets); 432 }, 433 434 /** 435 * Initializes a 9-slice sprite with an sprite frame and with the specified 436 * cap insets. 437 * Once the sprite is created, you can then call its "setContentSize:" method 438 * to resize the sprite will all it's 9-slice goodness intract. 439 * It respects the anchorPoint too. 440 * 441 * @param spriteFrame The sprite frame object. 442 * @param capInsets The values to use for the cap insets. 443 */ 444 initWithSpriteFrame: function (spriteFrame, capInsets) { 445 if(!spriteFrame || !spriteFrame.getTexture()) 446 throw "cc.Scale9Sprite.initWithSpriteFrame(): spriteFrame should be non-null and its texture should be non-null"; 447 448 capInsets = capInsets || cc.RectZero(); 449 var locLoaded = spriteFrame.textureLoaded(); 450 this._textureLoaded = locLoaded; 451 if(!locLoaded){ 452 spriteFrame.addLoadedEventListener(function(sender){ 453 // the texture is rotated on Canvas render mode, so isRotated always is false. 454 var preferredSize = this._preferredSize; 455 preferredSize = cc.size(preferredSize.width, preferredSize.height); 456 this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc.Browser.supportWebGL ? sender.isRotated() : false, this._capInsets); 457 this.setPreferredSize(preferredSize); 458 this._positionsAreDirty = true; 459 this._callLoadedEventCallbacks(); 460 },this); 461 } 462 var batchNode = cc.SpriteBatchNode.createWithTexture(spriteFrame.getTexture(), 9); 463 // the texture is rotated on Canvas render mode, so isRotated always is false. 464 return this.initWithBatchNode(batchNode, spriteFrame.getRect(), cc.Browser.supportWebGL ? spriteFrame.isRotated() : false, capInsets); 465 }, 466 467 /** 468 * Initializes a 9-slice sprite with an sprite frame name and with the specified 469 * cap insets. 470 * Once the sprite is created, you can then call its "setContentSize:" method 471 * to resize the sprite will all it's 9-slice goodness intract. 472 * It respects the anchorPoint too. 473 * 474 * @param spriteFrameName The sprite frame name. 475 * @param capInsets The values to use for the cap insets. 476 */ 477 initWithSpriteFrameName: function (spriteFrameName, capInsets) { 478 if(!spriteFrameName) 479 throw "cc.Scale9Sprite.initWithSpriteFrameName(): spriteFrameName should be non-null"; 480 capInsets = capInsets || cc.RectZero(); 481 482 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName); 483 if (frame == null) { 484 cc.log("cc.Scale9Sprite.initWithSpriteFrameName(): can't find the sprite frame by spriteFrameName"); 485 return false; 486 } 487 488 return this.initWithSpriteFrame(frame, capInsets); 489 }, 490 491 /** 492 * Creates and returns a new sprite object with the specified cap insets. 493 * You use this method to add cap insets to a sprite or to change the existing 494 * cap insets of a sprite. In both cases, you get back a new image and the 495 * original sprite remains untouched. 496 * 497 * @param capInsets The values to use for the cap insets. 498 */ 499 resizableSpriteWithCapInsets: function (capInsets) { 500 var pReturn = new cc.Scale9Sprite(); 501 if (pReturn && pReturn.initWithBatchNode(this._scale9Image, this._spriteRect, false, capInsets)) { 502 return pReturn; 503 } 504 return null; 505 }, 506 507 /** sets the premultipliedAlphaOpacity property. 508 If set to NO then opacity will be applied as: glColor(R,G,B,opacity); 509 If set to YES then oapcity will be applied as: glColor(opacity, opacity, opacity, opacity ); 510 Textures with premultiplied alpha will have this property by default on YES. Otherwise the default value is NO 511 @since v0.8 512 */ 513 setOpacityModifyRGB: function (value) { 514 if(!this._scale9Image){ 515 return; 516 } 517 this._opacityModifyRGB = value; 518 var scaleChildren = this._scale9Image.getChildren(); 519 if (scaleChildren) { 520 for (var i = 0, len = scaleChildren.length; i < len; i++) 521 scaleChildren[i].setOpacityModifyRGB(value); 522 } 523 }, 524 525 /** returns whether or not the opacity will be applied using glColor(R,G,B,opacity) or glColor(opacity, opacity, opacity, opacity); 526 @since v0.8 527 */ 528 isOpacityModifyRGB: function () { 529 return this._opacityModifyRGB; 530 }, 531 532 updateWithBatchNode: function (batchNode, originalRect, rotated, capInsets) { 533 var opacity = this.getOpacity(); 534 var color = this.getColor(); 535 var rect = cc.rect(originalRect.x, originalRect.y, originalRect.width, originalRect.height); 536 537 // Release old sprites 538 this.removeAllChildren(true); 539 540 if (this._scale9Image != batchNode){ 541 this._scale9Image = batchNode; 542 } 543 var tmpTexture = batchNode.getTexture(); 544 var locLoaded = tmpTexture.isLoaded(); 545 this._textureLoaded = locLoaded; 546 if(!locLoaded){ 547 tmpTexture.addLoadedEventListener(function(sender){ 548 this._positionsAreDirty = true; 549 this._callLoadedEventCallbacks(); 550 },this); 551 return; 552 } 553 var locScale9Image = this._scale9Image; 554 locScale9Image.removeAllChildren(true); 555 556 //this._capInsets = capInsets; 557 var locCapInsets = this._capInsets; 558 locCapInsets.x = capInsets.x; 559 locCapInsets.y = capInsets.y; 560 locCapInsets.width = capInsets.width; 561 locCapInsets.height = capInsets.height; 562 this._spriteFrameRotated = rotated; 563 564 var selTexture = locScale9Image.getTexture(); 565 566 // If there is no given rect 567 if (cc._rectEqualToZero(rect)) { 568 // Get the texture size as original 569 var textureSize = selTexture.getContentSize(); 570 rect = cc.rect(0, 0, textureSize.width, textureSize.height); 571 } 572 573 // Set the given rect's size as original size 574 this._spriteRect = rect; 575 var locSpriteRect = this._spriteRect; 576 locSpriteRect.x = rect.x; 577 locSpriteRect.y = rect.y; 578 locSpriteRect.width = rect.width; 579 locSpriteRect.height = rect.height; 580 581 var rectSize = rect._size; 582 this._originalSize.width = rectSize.width; 583 this._originalSize.height = rectSize.height; 584 585 var locPreferredSize = this._preferredSize; 586 if(locPreferredSize.width === 0 && locPreferredSize.height === 0){ 587 locPreferredSize.width = rectSize.width; 588 locPreferredSize.height = rectSize.height; 589 } 590 591 var locCapInsetsInternal = this._capInsetsInternal; 592 if(capInsets){ 593 locCapInsetsInternal.x = capInsets.x; 594 locCapInsetsInternal.y = capInsets.y; 595 locCapInsetsInternal.width = capInsets.width; 596 locCapInsetsInternal.height = capInsets.height; 597 } 598 var w = rectSize.width; 599 var h = rectSize.height; 600 601 // If there is no specified center region 602 if (cc._rectEqualToZero(locCapInsetsInternal)) { 603 // CCLog("... cap insets not specified : using default cap insets ..."); 604 locCapInsetsInternal.x = w / 3; 605 locCapInsetsInternal.y = h / 3; 606 locCapInsetsInternal.width = w / 3; 607 locCapInsetsInternal.height = h / 3; 608 } 609 610 var left_w = locCapInsetsInternal.x; 611 var center_w = locCapInsetsInternal.width; 612 var right_w = w - (left_w + center_w); 613 614 var top_h = locCapInsetsInternal.y; 615 var center_h = locCapInsetsInternal.height; 616 var bottom_h = h - (top_h + center_h); 617 618 // calculate rects 619 // ... top row 620 var x = 0.0; 621 var y = 0.0; 622 623 // top left 624 var lefttopbounds = cc.rect(x, y, left_w, top_h); 625 626 // top center 627 x += left_w; 628 var centertopbounds = cc.rect(x, y, center_w, top_h); 629 630 // top right 631 x += center_w; 632 var righttopbounds = cc.rect(x, y, right_w, top_h); 633 634 // ... center row 635 x = 0.0; 636 y = 0.0; 637 638 y += top_h; 639 // center left 640 var leftcenterbounds = cc.rect(x, y, left_w, center_h); 641 642 // center center 643 x += left_w; 644 var centerbounds = cc.rect(x, y, center_w, center_h); 645 646 // center right 647 x += center_w; 648 var rightcenterbounds = cc.rect(x, y, right_w, center_h); 649 650 // ... bottom row 651 x = 0.0; 652 y = 0.0; 653 y += top_h; 654 y += center_h; 655 656 // bottom left 657 var leftbottombounds = cc.rect(x, y, left_w, bottom_h); 658 659 // bottom center 660 x += left_w; 661 var centerbottombounds = cc.rect(x, y, center_w, bottom_h); 662 663 // bottom right 664 x += center_w; 665 var rightbottombounds = cc.rect(x, y, right_w, bottom_h); 666 667 var t = cc.AffineTransformMakeIdentity(); 668 if (!rotated) { 669 // CCLog("!rotated"); 670 t = cc.AffineTransformTranslate(t, rect.x, rect.y); 671 672 cc._RectApplyAffineTransformIn(centerbounds, t); 673 cc._RectApplyAffineTransformIn(rightbottombounds, t); 674 cc._RectApplyAffineTransformIn(leftbottombounds, t); 675 cc._RectApplyAffineTransformIn(righttopbounds, t); 676 cc._RectApplyAffineTransformIn(lefttopbounds, t); 677 cc._RectApplyAffineTransformIn(rightcenterbounds, t); 678 cc._RectApplyAffineTransformIn(leftcenterbounds, t); 679 cc._RectApplyAffineTransformIn(centerbottombounds, t); 680 cc._RectApplyAffineTransformIn(centertopbounds, t); 681 682 // Centre 683 this._centre = new cc.Sprite(); 684 this._centre.initWithTexture(selTexture, centerbounds); 685 locScale9Image.addChild(this._centre, 0, cc.POSITIONS_CENTRE); 686 687 // Top 688 this._top = new cc.Sprite(); 689 this._top.initWithTexture(selTexture, centertopbounds); 690 locScale9Image.addChild(this._top, 1, cc.POSITIONS_TOP); 691 692 // Bottom 693 this._bottom = new cc.Sprite(); 694 this._bottom.initWithTexture(selTexture, centerbottombounds); 695 locScale9Image.addChild(this._bottom, 1, cc.POSITIONS_BOTTOM); 696 697 // Left 698 this._left = new cc.Sprite(); 699 this._left.initWithTexture(selTexture, leftcenterbounds); 700 locScale9Image.addChild(this._left, 1, cc.POSITIONS_LEFT); 701 702 // Right 703 this._right = new cc.Sprite(); 704 this._right.initWithTexture(selTexture, rightcenterbounds); 705 locScale9Image.addChild(this._right, 1, cc.POSITIONS_RIGHT); 706 707 // Top left 708 this._topLeft = new cc.Sprite(); 709 this._topLeft.initWithTexture(selTexture, lefttopbounds); 710 locScale9Image.addChild(this._topLeft, 2, cc.POSITIONS_TOPLEFT); 711 712 // Top right 713 this._topRight = new cc.Sprite(); 714 this._topRight.initWithTexture(selTexture, righttopbounds); 715 locScale9Image.addChild(this._topRight, 2, cc.POSITIONS_TOPRIGHT); 716 717 // Bottom left 718 this._bottomLeft = new cc.Sprite(); 719 this._bottomLeft.initWithTexture(selTexture, leftbottombounds); 720 locScale9Image.addChild(this._bottomLeft, 2, cc.POSITIONS_BOTTOMLEFT); 721 722 // Bottom right 723 this._bottomRight = new cc.Sprite(); 724 this._bottomRight.initWithTexture(selTexture, rightbottombounds); 725 locScale9Image.addChild(this._bottomRight, 2, cc.POSITIONS_BOTTOMRIGHT); 726 } else { 727 // set up transformation of coordinates 728 // to handle the case where the sprite is stored rotated 729 // in the spritesheet 730 // CCLog("rotated"); 731 var rotatedcenterbounds = centerbounds; 732 var rotatedrightbottombounds = rightbottombounds; 733 var rotatedleftbottombounds = leftbottombounds; 734 var rotatedrighttopbounds = righttopbounds; 735 var rotatedlefttopbounds = lefttopbounds; 736 var rotatedrightcenterbounds = rightcenterbounds; 737 var rotatedleftcenterbounds = leftcenterbounds; 738 var rotatedcenterbottombounds = centerbottombounds; 739 var rotatedcentertopbounds = centertopbounds; 740 741 t = cc.AffineTransformTranslate(t, rect.height + rect.x, rect.y); 742 t = cc.AffineTransformRotate(t, 1.57079633); 743 744 centerbounds = cc.RectApplyAffineTransform(centerbounds, t); 745 rightbottombounds = cc.RectApplyAffineTransform(rightbottombounds, t); 746 leftbottombounds = cc.RectApplyAffineTransform(leftbottombounds, t); 747 righttopbounds = cc.RectApplyAffineTransform(righttopbounds, t); 748 lefttopbounds = cc.RectApplyAffineTransform(lefttopbounds, t); 749 rightcenterbounds = cc.RectApplyAffineTransform(rightcenterbounds, t); 750 leftcenterbounds = cc.RectApplyAffineTransform(leftcenterbounds, t); 751 centerbottombounds = cc.RectApplyAffineTransform(centerbottombounds, t); 752 centertopbounds = cc.RectApplyAffineTransform(centertopbounds, t); 753 754 rotatedcenterbounds.x = centerbounds.x; 755 rotatedcenterbounds.y = centerbounds.y; 756 757 rotatedrightbottombounds.x = rightbottombounds.x; 758 rotatedrightbottombounds.y = rightbottombounds.y; 759 760 rotatedleftbottombounds.x = leftbottombounds.x; 761 rotatedleftbottombounds.y = leftbottombounds.y; 762 763 rotatedrighttopbounds.x = righttopbounds.x; 764 rotatedrighttopbounds.y = righttopbounds.y; 765 766 rotatedlefttopbounds.x = lefttopbounds.x; 767 rotatedlefttopbounds.y = lefttopbounds.y; 768 769 rotatedrightcenterbounds.x = rightcenterbounds.x; 770 rotatedrightcenterbounds.y = rightcenterbounds.y; 771 772 rotatedleftcenterbounds.x = leftcenterbounds.x; 773 rotatedleftcenterbounds.y = leftcenterbounds.y; 774 775 rotatedcenterbottombounds.x = centerbottombounds.x; 776 rotatedcenterbottombounds.y = centerbottombounds.y; 777 778 rotatedcentertopbounds.x = centertopbounds.x; 779 rotatedcentertopbounds.y = centertopbounds.y; 780 781 // Centre 782 this._centre = new cc.Sprite(); 783 this._centre.initWithTexture(selTexture, rotatedcenterbounds, true); 784 locScale9Image.addChild(this._centre, 0, cc.POSITIONS_CENTRE); 785 786 // Top 787 this._top = new cc.Sprite(); 788 this._top.initWithTexture(selTexture, rotatedcentertopbounds, true); 789 locScale9Image.addChild(this._top, 1, cc.POSITIONS_TOP); 790 791 // Bottom 792 this._bottom = new cc.Sprite(); 793 this._bottom.initWithTexture(selTexture, rotatedcenterbottombounds, true); 794 locScale9Image.addChild(this._bottom, 1, cc.POSITIONS_BOTTOM); 795 796 // Left 797 this._left = new cc.Sprite(); 798 this._left.initWithTexture(selTexture, rotatedleftcenterbounds, true); 799 locScale9Image.addChild(this._left, 1, cc.POSITIONS_LEFT); 800 801 // Right 802 this._right = new cc.Sprite(); 803 this._right.initWithTexture(selTexture, rotatedrightcenterbounds, true); 804 locScale9Image.addChild(this._right, 1, cc.POSITIONS_RIGHT); 805 806 // Top left 807 this._topLeft = new cc.Sprite(); 808 this._topLeft.initWithTexture(selTexture, rotatedlefttopbounds, true); 809 locScale9Image.addChild(this._topLeft, 2, cc.POSITIONS_TOPLEFT); 810 811 // Top right 812 this._topRight = new cc.Sprite(); 813 this._topRight.initWithTexture(selTexture, rotatedrighttopbounds, true); 814 locScale9Image.addChild(this._topRight, 2, cc.POSITIONS_TOPRIGHT); 815 816 // Bottom left 817 this._bottomLeft = new cc.Sprite(); 818 this._bottomLeft.initWithTexture(selTexture, rotatedleftbottombounds, true); 819 locScale9Image.addChild(this._bottomLeft, 2, cc.POSITIONS_BOTTOMLEFT); 820 821 // Bottom right 822 this._bottomRight = new cc.Sprite(); 823 this._bottomRight.initWithTexture(selTexture, rotatedrightbottombounds, true); 824 locScale9Image.addChild(this._bottomRight, 2, cc.POSITIONS_BOTTOMRIGHT); 825 } 826 827 this.setContentSize(rect._size); 828 this.addChild(locScale9Image); 829 830 if (this._spritesGenerated) { 831 // Restore color and opacity 832 this.setOpacity(opacity); 833 if(color.r !== 255 || color.g !== 255 || color.b !== 255){ 834 this.setColor(color); 835 } 836 } 837 this._spritesGenerated = true; 838 return true; 839 }, 840 841 setSpriteFrame: function (spriteFrame) { 842 var batchNode = cc.SpriteBatchNode.createWithTexture(spriteFrame.getTexture(), 9); 843 // the texture is rotated on Canvas render mode, so isRotated always is false. 844 var locLoaded = spriteFrame.textureLoaded(); 845 this._textureLoaded = locLoaded; 846 if(!locLoaded){ 847 spriteFrame.addLoadedEventListener(function(sender){ 848 // the texture is rotated on Canvas render mode, so isRotated always is false. 849 var preferredSize = this._preferredSize; 850 preferredSize = cc.size(preferredSize.width, preferredSize.height); 851 this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc.Browser.supportWebGL ? sender.isRotated() : false, this._capInsets); 852 this.setPreferredSize(preferredSize); 853 this._positionsAreDirty = true; 854 this._callLoadedEventCallbacks(); 855 },this); 856 } 857 this.updateWithBatchNode(batchNode, spriteFrame.getRect(), cc.Browser.supportWebGL ? spriteFrame.isRotated() : false, cc.RectZero()); 858 859 // Reset insets 860 this._insetLeft = 0; 861 this._insetTop = 0; 862 this._insetRight = 0; 863 this._insetBottom = 0; 864 } 865 }); 866 867 /** 868 * Creates a 9-slice sprite with a texture file, a delimitation zone and 869 * with the specified cap insets. 870 * 871 * @see initWithFile:rect:centerRegion: 872 */ 873 cc.Scale9Sprite.create = function (file, rect, capInsets) { 874 var pReturn; 875 if (arguments.length === 2) { 876 if (typeof(file) == "string") { 877 pReturn = new cc.Scale9Sprite(); 878 if (pReturn && pReturn.initWithFile(file, rect)) { 879 return pReturn; 880 } 881 } else if (file instanceof cc.Rect) { 882 pReturn = new cc.Scale9Sprite(); 883 if (pReturn && pReturn.initWithFile(file, capInsets)) { 884 return pReturn; 885 } 886 } 887 } else if (arguments.length === 3) { 888 pReturn = new cc.Scale9Sprite(); 889 if (pReturn && pReturn.initWithFile(file, rect, capInsets)) { 890 return pReturn; 891 } 892 } else if (arguments.length === 1) { 893 pReturn = new cc.Scale9Sprite(); 894 if (pReturn && pReturn.initWithFile(file)) { 895 return pReturn; 896 } 897 } else if (arguments.length === 0) { 898 pReturn = new cc.Scale9Sprite(); 899 if (pReturn && pReturn.init()) { 900 return pReturn; 901 } 902 } 903 return null; 904 }; 905 906 cc.Scale9Sprite.createWithSpriteFrame = function (spriteFrame, capInsets) { 907 var pReturn = new cc.Scale9Sprite(); 908 if (pReturn && pReturn.initWithSpriteFrame(spriteFrame, capInsets)) { 909 return pReturn; 910 } 911 return null; 912 }; 913 914 cc.Scale9Sprite.createWithSpriteFrameName = function (spriteFrameName, capInsets) { 915 if(!spriteFrameName) 916 throw "cc.Scale9Sprite.createWithSpriteFrameName(): spriteFrameName should be non-null"; 917 var pReturn = new cc.Scale9Sprite(); 918 if (pReturn && pReturn.initWithSpriteFrameName(spriteFrameName, capInsets)) 919 return pReturn; 920 return null; 921 }; 922