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