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 cc.Node.prototype.setContentSize.call(this, size, height); 354 this._positionsAreDirty = true; 355 }, 356 357 visit: function (ctx) { 358 if (this._positionsAreDirty) { 359 this._updatePositions(); 360 this._positionsAreDirty = false; 361 } 362 cc.NodeRGBA.prototype.visit.call(this, ctx); 363 }, 364 365 init: function () { 366 return this.initWithBatchNode(null, cc.RectZero(), false, cc.RectZero()); 367 }, 368 369 initWithBatchNode: function (batchNode, rect, rotated, capInsets) { 370 if (capInsets === undefined) { 371 capInsets = rotated; 372 rotated = false; 373 } 374 375 if (batchNode) { 376 this.updateWithBatchNode(batchNode, rect, rotated, capInsets); 377 } 378 this.setAnchorPoint(0.5, 0.5); 379 this._positionsAreDirty = true; 380 return true; 381 }, 382 383 /** 384 * Initializes a 9-slice sprite with a texture file, a delimitation zone and 385 * with the specified cap insets. 386 * Once the sprite is created, you can then call its "setContentSize:" method 387 * to resize the sprite will all it's 9-slice goodness intact. 388 * It respects the anchorPoint too. 389 * 390 * @param file The name of the texture file. 391 * @param rect The rectangle that describes the sub-part of the texture that 392 * is the whole image. If the shape is the whole texture, set this to the 393 * texture's full rect. 394 * @param capInsets The values to use for the cap insets. 395 */ 396 initWithFile: function (file, rect, capInsets) { 397 if (file instanceof cc.Rect) { 398 file = arguments[1]; 399 capInsets = arguments[0]; 400 rect = cc.RectZero(); 401 } else { 402 rect = rect || cc.RectZero(); 403 capInsets = capInsets || cc.RectZero(); 404 } 405 406 if(!file) 407 throw "cc.Scale9Sprite.initWithFile(): file should be non-null"; 408 409 var texture = cc.TextureCache.getInstance().textureForKey(file); 410 if (!texture) { 411 texture = cc.TextureCache.getInstance().addImage(file); 412 var locLoaded = texture.isLoaded(); 413 this._textureLoaded = locLoaded; 414 if(!locLoaded){ 415 texture.addLoadedEventListener(function(sender){ 416 // the texture is rotated on Canvas render mode, so isRotated always is false. 417 var preferredSize = this._preferredSize; 418 preferredSize = cc.size(preferredSize.width, preferredSize.height); 419 var size = sender.getContentSize(); 420 this.updateWithBatchNode(this._scale9Image, cc.rect(0,0,size.width,size.height), false, this._capInsets); 421 this.setPreferredSize(preferredSize); 422 this._positionsAreDirty = true; 423 this._callLoadedEventCallbacks(); 424 }, this); 425 } 426 } 427 var batchnode = cc.SpriteBatchNode.create(file, 9); 428 return this.initWithBatchNode(batchnode, rect, false, capInsets); 429 }, 430 431 /** 432 * Initializes a 9-slice sprite with an sprite frame and with the specified 433 * cap insets. 434 * Once the sprite is created, you can then call its "setContentSize:" method 435 * to resize the sprite will all it's 9-slice goodness intract. 436 * It respects the anchorPoint too. 437 * 438 * @param spriteFrame The sprite frame object. 439 * @param capInsets The values to use for the cap insets. 440 */ 441 initWithSpriteFrame: function (spriteFrame, capInsets) { 442 if(!spriteFrame || !spriteFrame.getTexture()) 443 throw "cc.Scale9Sprite.initWithSpriteFrame(): spriteFrame should be non-null and its texture should be non-null"; 444 445 capInsets = capInsets || cc.RectZero(); 446 var locLoaded = spriteFrame.textureLoaded(); 447 this._textureLoaded = locLoaded; 448 if(!locLoaded){ 449 spriteFrame.addLoadedEventListener(function(sender){ 450 // the texture is rotated on Canvas render mode, so isRotated always is false. 451 var preferredSize = this._preferredSize; 452 preferredSize = cc.size(preferredSize.width, preferredSize.height); 453 this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc.Browser.supportWebGL ? sender.isRotated() : false, this._capInsets); 454 this.setPreferredSize(preferredSize); 455 this._positionsAreDirty = true; 456 this._callLoadedEventCallbacks(); 457 },this); 458 } 459 var batchNode = cc.SpriteBatchNode.createWithTexture(spriteFrame.getTexture(), 9); 460 // the texture is rotated on Canvas render mode, so isRotated always is false. 461 return this.initWithBatchNode(batchNode, spriteFrame.getRect(), cc.Browser.supportWebGL ? spriteFrame.isRotated() : false, capInsets); 462 }, 463 464 /** 465 * Initializes a 9-slice sprite with an sprite frame name and with the specified 466 * cap insets. 467 * Once the sprite is created, you can then call its "setContentSize:" method 468 * to resize the sprite will all it's 9-slice goodness intract. 469 * It respects the anchorPoint too. 470 * 471 * @param spriteFrameName The sprite frame name. 472 * @param capInsets The values to use for the cap insets. 473 */ 474 initWithSpriteFrameName: function (spriteFrameName, capInsets) { 475 if(!spriteFrameName) 476 throw "cc.Scale9Sprite.initWithSpriteFrameName(): spriteFrameName should be non-null"; 477 capInsets = capInsets || cc.RectZero(); 478 479 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName); 480 if (frame == null) { 481 cc.log("cc.Scale9Sprite.initWithSpriteFrameName(): can't find the sprite frame by spriteFrameName"); 482 return false; 483 } 484 485 return this.initWithSpriteFrame(frame, capInsets); 486 }, 487 488 /** 489 * Creates and returns a new sprite object with the specified cap insets. 490 * You use this method to add cap insets to a sprite or to change the existing 491 * cap insets of a sprite. In both cases, you get back a new image and the 492 * original sprite remains untouched. 493 * 494 * @param capInsets The values to use for the cap insets. 495 */ 496 resizableSpriteWithCapInsets: function (capInsets) { 497 var pReturn = new cc.Scale9Sprite(); 498 if (pReturn && pReturn.initWithBatchNode(this._scale9Image, this._spriteRect, false, capInsets)) { 499 return pReturn; 500 } 501 return null; 502 }, 503 504 /** sets the premultipliedAlphaOpacity property. 505 If set to NO then opacity will be applied as: glColor(R,G,B,opacity); 506 If set to YES then oapcity will be applied as: glColor(opacity, opacity, opacity, opacity ); 507 Textures with premultiplied alpha will have this property by default on YES. Otherwise the default value is NO 508 @since v0.8 509 */ 510 setOpacityModifyRGB: function (value) { 511 if(!this._scale9Image){ 512 return; 513 } 514 this._opacityModifyRGB = value; 515 var scaleChildren = this._scale9Image.getChildren(); 516 if (scaleChildren) { 517 for (var i = 0, len = scaleChildren.length; i < len; i++) 518 scaleChildren[i].setOpacityModifyRGB(value); 519 } 520 }, 521 522 /** returns whether or not the opacity will be applied using glColor(R,G,B,opacity) or glColor(opacity, opacity, opacity, opacity); 523 @since v0.8 524 */ 525 isOpacityModifyRGB: function () { 526 return this._opacityModifyRGB; 527 }, 528 529 updateWithBatchNode: function (batchNode, originalRect, rotated, capInsets) { 530 var opacity = this.getOpacity(); 531 var color = this.getColor(); 532 var rect = cc.rect(originalRect.x, originalRect.y, originalRect.width, originalRect.height); 533 534 // Release old sprites 535 this.removeAllChildren(true); 536 537 if (this._scale9Image != batchNode){ 538 this._scale9Image = batchNode; 539 } 540 var tmpTexture = batchNode.getTexture(); 541 var locLoaded = tmpTexture.isLoaded(); 542 this._textureLoaded = locLoaded; 543 if(!locLoaded){ 544 tmpTexture.addLoadedEventListener(function(sender){ 545 this._positionsAreDirty = true; 546 this._callLoadedEventCallbacks(); 547 },this); 548 return; 549 } 550 var locScale9Image = this._scale9Image; 551 locScale9Image.removeAllChildren(true); 552 553 //this._capInsets = capInsets; 554 var locCapInsets = this._capInsets; 555 locCapInsets.x = capInsets.x; 556 locCapInsets.y = capInsets.y; 557 locCapInsets.width = capInsets.width; 558 locCapInsets.height = capInsets.height; 559 this._spriteFrameRotated = rotated; 560 561 var selTexture = locScale9Image.getTexture(); 562 563 // If there is no given rect 564 if (cc._rectEqualToZero(rect)) { 565 // Get the texture size as original 566 var textureSize = selTexture.getContentSize(); 567 rect = cc.rect(0, 0, textureSize.width, textureSize.height); 568 } 569 570 // Set the given rect's size as original size 571 this._spriteRect = rect; 572 var locSpriteRect = this._spriteRect; 573 locSpriteRect.x = rect.x; 574 locSpriteRect.y = rect.y; 575 locSpriteRect.width = rect.width; 576 locSpriteRect.height = rect.height; 577 578 var rectSize = rect._size; 579 this._originalSize.width = rectSize.width; 580 this._originalSize.height = rectSize.height; 581 582 var locPreferredSize = this._preferredSize; 583 if(locPreferredSize.width === 0 && locPreferredSize.height === 0){ 584 locPreferredSize.width = rectSize.width; 585 locPreferredSize.height = rectSize.height; 586 } 587 588 var locCapInsetsInternal = this._capInsetsInternal; 589 if(capInsets){ 590 locCapInsetsInternal.x = capInsets.x; 591 locCapInsetsInternal.y = capInsets.y; 592 locCapInsetsInternal.width = capInsets.width; 593 locCapInsetsInternal.height = capInsets.height; 594 } 595 var w = rectSize.width; 596 var h = rectSize.height; 597 598 // If there is no specified center region 599 if (cc._rectEqualToZero(locCapInsetsInternal)) { 600 // CCLog("... cap insets not specified : using default cap insets ..."); 601 locCapInsetsInternal.x = w / 3; 602 locCapInsetsInternal.y = h / 3; 603 locCapInsetsInternal.width = w / 3; 604 locCapInsetsInternal.height = h / 3; 605 } 606 607 var left_w = locCapInsetsInternal.x; 608 var center_w = locCapInsetsInternal.width; 609 var right_w = w - (left_w + center_w); 610 611 var top_h = locCapInsetsInternal.y; 612 var center_h = locCapInsetsInternal.height; 613 var bottom_h = h - (top_h + center_h); 614 615 // calculate rects 616 // ... top row 617 var x = 0.0; 618 var y = 0.0; 619 620 // top left 621 var lefttopbounds = cc.rect(x, y, left_w, top_h); 622 623 // top center 624 x += left_w; 625 var centertopbounds = cc.rect(x, y, center_w, top_h); 626 627 // top right 628 x += center_w; 629 var righttopbounds = cc.rect(x, y, right_w, top_h); 630 631 // ... center row 632 x = 0.0; 633 y = 0.0; 634 635 y += top_h; 636 // center left 637 var leftcenterbounds = cc.rect(x, y, left_w, center_h); 638 639 // center center 640 x += left_w; 641 var centerbounds = cc.rect(x, y, center_w, center_h); 642 643 // center right 644 x += center_w; 645 var rightcenterbounds = cc.rect(x, y, right_w, center_h); 646 647 // ... bottom row 648 x = 0.0; 649 y = 0.0; 650 y += top_h; 651 y += center_h; 652 653 // bottom left 654 var leftbottombounds = cc.rect(x, y, left_w, bottom_h); 655 656 // bottom center 657 x += left_w; 658 var centerbottombounds = cc.rect(x, y, center_w, bottom_h); 659 660 // bottom right 661 x += center_w; 662 var rightbottombounds = cc.rect(x, y, right_w, bottom_h); 663 664 var t = cc.AffineTransformMakeIdentity(); 665 if (!rotated) { 666 // CCLog("!rotated"); 667 t = cc.AffineTransformTranslate(t, rect.x, rect.y); 668 669 cc._RectApplyAffineTransformIn(centerbounds, t); 670 cc._RectApplyAffineTransformIn(rightbottombounds, t); 671 cc._RectApplyAffineTransformIn(leftbottombounds, t); 672 cc._RectApplyAffineTransformIn(righttopbounds, t); 673 cc._RectApplyAffineTransformIn(lefttopbounds, t); 674 cc._RectApplyAffineTransformIn(rightcenterbounds, t); 675 cc._RectApplyAffineTransformIn(leftcenterbounds, t); 676 cc._RectApplyAffineTransformIn(centerbottombounds, t); 677 cc._RectApplyAffineTransformIn(centertopbounds, t); 678 679 // Centre 680 this._centre = new cc.Sprite(); 681 this._centre.initWithTexture(selTexture, centerbounds); 682 locScale9Image.addChild(this._centre, 0, cc.POSITIONS_CENTRE); 683 684 // Top 685 this._top = new cc.Sprite(); 686 this._top.initWithTexture(selTexture, centertopbounds); 687 locScale9Image.addChild(this._top, 1, cc.POSITIONS_TOP); 688 689 // Bottom 690 this._bottom = new cc.Sprite(); 691 this._bottom.initWithTexture(selTexture, centerbottombounds); 692 locScale9Image.addChild(this._bottom, 1, cc.POSITIONS_BOTTOM); 693 694 // Left 695 this._left = new cc.Sprite(); 696 this._left.initWithTexture(selTexture, leftcenterbounds); 697 locScale9Image.addChild(this._left, 1, cc.POSITIONS_LEFT); 698 699 // Right 700 this._right = new cc.Sprite(); 701 this._right.initWithTexture(selTexture, rightcenterbounds); 702 locScale9Image.addChild(this._right, 1, cc.POSITIONS_RIGHT); 703 704 // Top left 705 this._topLeft = new cc.Sprite(); 706 this._topLeft.initWithTexture(selTexture, lefttopbounds); 707 locScale9Image.addChild(this._topLeft, 2, cc.POSITIONS_TOPLEFT); 708 709 // Top right 710 this._topRight = new cc.Sprite(); 711 this._topRight.initWithTexture(selTexture, righttopbounds); 712 locScale9Image.addChild(this._topRight, 2, cc.POSITIONS_TOPRIGHT); 713 714 // Bottom left 715 this._bottomLeft = new cc.Sprite(); 716 this._bottomLeft.initWithTexture(selTexture, leftbottombounds); 717 locScale9Image.addChild(this._bottomLeft, 2, cc.POSITIONS_BOTTOMLEFT); 718 719 // Bottom right 720 this._bottomRight = new cc.Sprite(); 721 this._bottomRight.initWithTexture(selTexture, rightbottombounds); 722 locScale9Image.addChild(this._bottomRight, 2, cc.POSITIONS_BOTTOMRIGHT); 723 } else { 724 // set up transformation of coordinates 725 // to handle the case where the sprite is stored rotated 726 // in the spritesheet 727 // CCLog("rotated"); 728 var rotatedcenterbounds = centerbounds; 729 var rotatedrightbottombounds = rightbottombounds; 730 var rotatedleftbottombounds = leftbottombounds; 731 var rotatedrighttopbounds = righttopbounds; 732 var rotatedlefttopbounds = lefttopbounds; 733 var rotatedrightcenterbounds = rightcenterbounds; 734 var rotatedleftcenterbounds = leftcenterbounds; 735 var rotatedcenterbottombounds = centerbottombounds; 736 var rotatedcentertopbounds = centertopbounds; 737 738 t = cc.AffineTransformTranslate(t, rect.height + rect.x, rect.y); 739 t = cc.AffineTransformRotate(t, 1.57079633); 740 741 centerbounds = cc.RectApplyAffineTransform(centerbounds, t); 742 rightbottombounds = cc.RectApplyAffineTransform(rightbottombounds, t); 743 leftbottombounds = cc.RectApplyAffineTransform(leftbottombounds, t); 744 righttopbounds = cc.RectApplyAffineTransform(righttopbounds, t); 745 lefttopbounds = cc.RectApplyAffineTransform(lefttopbounds, t); 746 rightcenterbounds = cc.RectApplyAffineTransform(rightcenterbounds, t); 747 leftcenterbounds = cc.RectApplyAffineTransform(leftcenterbounds, t); 748 centerbottombounds = cc.RectApplyAffineTransform(centerbottombounds, t); 749 centertopbounds = cc.RectApplyAffineTransform(centertopbounds, t); 750 751 rotatedcenterbounds.x = centerbounds.x; 752 rotatedcenterbounds.y = centerbounds.y; 753 754 rotatedrightbottombounds.x = rightbottombounds.x; 755 rotatedrightbottombounds.y = rightbottombounds.y; 756 757 rotatedleftbottombounds.x = leftbottombounds.x; 758 rotatedleftbottombounds.y = leftbottombounds.y; 759 760 rotatedrighttopbounds.x = righttopbounds.x; 761 rotatedrighttopbounds.y = righttopbounds.y; 762 763 rotatedlefttopbounds.x = lefttopbounds.x; 764 rotatedlefttopbounds.y = lefttopbounds.y; 765 766 rotatedrightcenterbounds.x = rightcenterbounds.x; 767 rotatedrightcenterbounds.y = rightcenterbounds.y; 768 769 rotatedleftcenterbounds.x = leftcenterbounds.x; 770 rotatedleftcenterbounds.y = leftcenterbounds.y; 771 772 rotatedcenterbottombounds.x = centerbottombounds.x; 773 rotatedcenterbottombounds.y = centerbottombounds.y; 774 775 rotatedcentertopbounds.x = centertopbounds.x; 776 rotatedcentertopbounds.y = centertopbounds.y; 777 778 // Centre 779 this._centre = new cc.Sprite(); 780 this._centre.initWithTexture(selTexture, rotatedcenterbounds, true); 781 locScale9Image.addChild(this._centre, 0, cc.POSITIONS_CENTRE); 782 783 // Top 784 this._top = new cc.Sprite(); 785 this._top.initWithTexture(selTexture, rotatedcentertopbounds, true); 786 locScale9Image.addChild(this._top, 1, cc.POSITIONS_TOP); 787 788 // Bottom 789 this._bottom = new cc.Sprite(); 790 this._bottom.initWithTexture(selTexture, rotatedcenterbottombounds, true); 791 locScale9Image.addChild(this._bottom, 1, cc.POSITIONS_BOTTOM); 792 793 // Left 794 this._left = new cc.Sprite(); 795 this._left.initWithTexture(selTexture, rotatedleftcenterbounds, true); 796 locScale9Image.addChild(this._left, 1, cc.POSITIONS_LEFT); 797 798 // Right 799 this._right = new cc.Sprite(); 800 this._right.initWithTexture(selTexture, rotatedrightcenterbounds, true); 801 locScale9Image.addChild(this._right, 1, cc.POSITIONS_RIGHT); 802 803 // Top left 804 this._topLeft = new cc.Sprite(); 805 this._topLeft.initWithTexture(selTexture, rotatedlefttopbounds, true); 806 locScale9Image.addChild(this._topLeft, 2, cc.POSITIONS_TOPLEFT); 807 808 // Top right 809 this._topRight = new cc.Sprite(); 810 this._topRight.initWithTexture(selTexture, rotatedrighttopbounds, true); 811 locScale9Image.addChild(this._topRight, 2, cc.POSITIONS_TOPRIGHT); 812 813 // Bottom left 814 this._bottomLeft = new cc.Sprite(); 815 this._bottomLeft.initWithTexture(selTexture, rotatedleftbottombounds, true); 816 locScale9Image.addChild(this._bottomLeft, 2, cc.POSITIONS_BOTTOMLEFT); 817 818 // Bottom right 819 this._bottomRight = new cc.Sprite(); 820 this._bottomRight.initWithTexture(selTexture, rotatedrightbottombounds, true); 821 locScale9Image.addChild(this._bottomRight, 2, cc.POSITIONS_BOTTOMRIGHT); 822 } 823 824 this.setContentSize(rect._size); 825 this.addChild(locScale9Image); 826 827 if (this._spritesGenerated) { 828 // Restore color and opacity 829 this.setOpacity(opacity); 830 if(color.r !== 255 || color.g !== 255 || color.b !== 255){ 831 this.setColor(color); 832 } 833 } 834 this._spritesGenerated = true; 835 return true; 836 }, 837 838 setSpriteFrame: function (spriteFrame) { 839 var batchNode = cc.SpriteBatchNode.createWithTexture(spriteFrame.getTexture(), 9); 840 // the texture is rotated on Canvas render mode, so isRotated always is false. 841 var locLoaded = spriteFrame.textureLoaded(); 842 this._textureLoaded = locLoaded; 843 if(!locLoaded){ 844 spriteFrame.addLoadedEventListener(function(sender){ 845 // the texture is rotated on Canvas render mode, so isRotated always is false. 846 var preferredSize = this._preferredSize; 847 preferredSize = cc.size(preferredSize.width, preferredSize.height); 848 this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc.Browser.supportWebGL ? sender.isRotated() : false, this._capInsets); 849 this.setPreferredSize(preferredSize); 850 this._positionsAreDirty = true; 851 this._callLoadedEventCallbacks(); 852 },this); 853 } 854 this.updateWithBatchNode(batchNode, spriteFrame.getRect(), cc.Browser.supportWebGL ? spriteFrame.isRotated() : false, cc.RectZero()); 855 856 // Reset insets 857 this._insetLeft = 0; 858 this._insetTop = 0; 859 this._insetRight = 0; 860 this._insetBottom = 0; 861 } 862 }); 863 864 /** 865 * Creates a 9-slice sprite with a texture file, a delimitation zone and 866 * with the specified cap insets. 867 * 868 * @see initWithFile:rect:centerRegion: 869 */ 870 cc.Scale9Sprite.create = function (file, rect, capInsets) { 871 var pReturn; 872 if (arguments.length === 2) { 873 if (typeof(file) == "string") { 874 pReturn = new cc.Scale9Sprite(); 875 if (pReturn && pReturn.initWithFile(file, rect)) { 876 return pReturn; 877 } 878 } else if (file instanceof cc.Rect) { 879 pReturn = new cc.Scale9Sprite(); 880 if (pReturn && pReturn.initWithFile(file, capInsets)) { 881 return pReturn; 882 } 883 } 884 } else if (arguments.length === 3) { 885 pReturn = new cc.Scale9Sprite(); 886 if (pReturn && pReturn.initWithFile(file, rect, capInsets)) { 887 return pReturn; 888 } 889 } else if (arguments.length === 1) { 890 pReturn = new cc.Scale9Sprite(); 891 if (pReturn && pReturn.initWithFile(file)) { 892 return pReturn; 893 } 894 } else if (arguments.length === 0) { 895 pReturn = new cc.Scale9Sprite(); 896 if (pReturn && pReturn.init()) { 897 return pReturn; 898 } 899 } 900 return null; 901 }; 902 903 cc.Scale9Sprite.createWithSpriteFrame = function (spriteFrame, capInsets) { 904 var pReturn = new cc.Scale9Sprite(); 905 if (pReturn && pReturn.initWithSpriteFrame(spriteFrame, capInsets)) { 906 return pReturn; 907 } 908 return null; 909 }; 910 911 cc.Scale9Sprite.createWithSpriteFrameName = function (spriteFrameName, capInsets) { 912 if(!spriteFrameName) 913 throw "cc.Scale9Sprite.createWithSpriteFrameName(): spriteFrameName should be non-null"; 914 var pReturn = new cc.Scale9Sprite(); 915 if (pReturn && pReturn.initWithSpriteFrameName(spriteFrameName, capInsets)) 916 return pReturn; 917 return null; 918 }; 919