1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies Inc.
  5  Copyright (c) 2012 Neofect. All rights reserved.
  6 
  7  http://www.cocos2d-x.org
  8 
  9  Permission is hereby granted, free of charge, to any person obtaining a copy
 10  of this software and associated documentation files (the "Software"), to deal
 11  in the Software without restriction, including without limitation the rights
 12  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 13  copies of the Software, and to permit persons to whom the Software is
 14  furnished to do so, subject to the following conditions:
 15 
 16  The above copyright notice and this permission notice shall be included in
 17  all copies or substantial portions of the Software.
 18 
 19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 24  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 25  THE SOFTWARE.
 26 
 27  Created by Jung Sang-Taik on 2012-03-16
 28  ****************************************************************************/
 29 
 30 /**
 31  * <p>
 32  * A 9-slice sprite for cocos2d UI.                                                                    <br/>
 33  *                                                                                                     <br/>
 34  * 9-slice scaling allows you to specify how scaling is applied                                        <br/>
 35  * to specific areas of a sprite. With 9-slice scaling (3x3 grid),                                     <br/>
 36  * you can ensure that the sprite does not become distorted when                                       <br/>
 37  * scaled.                                                                                             <br/>
 38  * @note: it will refactor in v3.1                                                                    <br/>
 39  * @see http://yannickloriot.com/library/ios/cccontrolextension/Classes/CCScale9Sprite.html            <br/>
 40  * </p>
 41  * @class
 42  * @extends cc.Node
 43  *
 44  * @property {cc.Size}  preferredSize   - The preferred size of the 9-slice sprite
 45  * @property {cc.Rect}  capInsets       - The cap insets of the 9-slice sprite
 46  * @property {Number}   insetLeft       - The left inset of the 9-slice sprite
 47  * @property {Number}   insetTop        - The top inset of the 9-slice sprite
 48  * @property {Number}   insetRight      - The right inset of the 9-slice sprite
 49  * @property {Number}   insetBottom     - The bottom inset of the 9-slice sprite
 50  */
 51 
 52 ccui.Scale9Sprite = cc.Scale9Sprite = cc.Node.extend(/** @lends ccui.Scale9Sprite# */{
 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     _scale9Enabled: true,
 69     _brightState: 0,
 70     _renderers: null,
 71 
 72     _opacityModifyRGB: false,
 73 
 74     _originalSize: null,
 75     _preferredSize: null,
 76     _opacity: 0,
 77     _color: null,
 78     _capInsets: null,
 79     _insetLeft: 0,
 80     _insetTop: 0,
 81     _insetRight: 0,
 82     _insetBottom: 0,
 83 
 84     _spritesGenerated: false,
 85     _spriteFrameRotated: false,
 86     _textureLoaded:false,
 87     _className:"Scale9Sprite",
 88 
 89     //v3.3
 90     _flippedX: false,
 91     _flippedY: false,
 92 
 93     /**
 94      * return  texture is loaded
 95      * @returns {boolean}
 96      */
 97     textureLoaded:function(){
 98         return this._textureLoaded;
 99     },
100 
101     /**
102      * add texture loaded event listener
103      * @param {Function} callback
104      * @param {Object} target
105      * @deprecated since 3.1, please use addEventListener instead
106      */
107     addLoadedEventListener:function(callback, target){
108         this.addEventListener("load", callback, target);
109     },
110 
111     _updateCapInset: function () {
112         var insets, locInsetLeft = this._insetLeft, locInsetTop = this._insetTop, locInsetRight = this._insetRight;
113         var locSpriteRect = this._spriteRect, locInsetBottom = this._insetBottom;
114         if (locInsetLeft === 0 && locInsetTop === 0 && locInsetRight === 0 && locInsetBottom === 0) {
115             insets = cc.rect(0, 0, 0, 0);
116         } else {
117             insets = this._spriteFrameRotated ? cc.rect(locInsetBottom, locInsetLeft,
118                     locSpriteRect.width - locInsetRight - locInsetLeft,
119                     locSpriteRect.height - locInsetTop - locInsetBottom) :
120                 cc.rect(locInsetLeft, locInsetTop,
121                         locSpriteRect.width - locInsetLeft - locInsetRight,
122                         locSpriteRect.height - locInsetTop - locInsetBottom);
123         }
124         this.setCapInsets(insets);
125     },
126 
127     _updatePositions: function () {
128         // Check that instances are non-NULL
129         if (!((this._topLeft) && (this._topRight) && (this._bottomRight) &&
130             (this._bottomLeft) && (this._centre))) {
131             // if any of the above sprites are NULL, return
132             return;
133         }
134 
135         var size = this._contentSize;
136         var locTopLeft = this._topLeft, locTopRight = this._topRight, locBottomRight = this._bottomRight, locBottomLeft = this._bottomLeft;
137         var locLeft = this._left, locRight = this._right, locTop = this._top, locBottom = this._bottom;
138         var locCenter = this._centre, locCenterContentSize = this._centre.getContentSize();
139         var locTopLeftContentSize = locTopLeft.getContentSize();
140         var locBottomLeftContentSize = locBottomLeft.getContentSize();
141 
142         var sizableWidth = size.width - locTopLeftContentSize.width - locTopRight.getContentSize().width;
143         var sizableHeight = size.height - locTopLeftContentSize.height - locBottomRight.getContentSize().height;
144 
145         var horizontalScale = sizableWidth / locCenterContentSize.width;
146         var verticalScale = sizableHeight / locCenterContentSize.height;
147 
148         var rescaledWidth = locCenterContentSize.width * horizontalScale;
149         var rescaledHeight = locCenterContentSize.height * verticalScale;
150 
151         var leftWidth = locBottomLeftContentSize.width;
152         var bottomHeight = locBottomLeftContentSize.height;
153         var centerOffset = cc.p(this._offset.x * horizontalScale, this._offset.y*verticalScale);
154 
155         if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) {
156             //browser is in canvas mode, need to manually control rounding to prevent overlapping pixels
157             var roundedRescaledWidth = Math.round(rescaledWidth);
158             if (rescaledWidth !== roundedRescaledWidth) {
159                 rescaledWidth = roundedRescaledWidth;
160                 horizontalScale = rescaledWidth / locCenterContentSize.width;
161             }
162             var roundedRescaledHeight = Math.round(rescaledHeight);
163             if (rescaledHeight !== roundedRescaledHeight) {
164                 rescaledHeight = roundedRescaledHeight;
165                 verticalScale = rescaledHeight / locCenterContentSize.height;
166             }
167         }
168 
169         locCenter.setScaleX(horizontalScale);
170         locCenter.setScaleY(verticalScale);
171 
172         locBottomLeft.setAnchorPoint(1, 1);
173         locBottomLeft.setPosition(leftWidth,bottomHeight);
174 
175         locBottomRight.setAnchorPoint(0, 1);
176         locBottomRight.setPosition(leftWidth+rescaledWidth,bottomHeight);
177 
178 
179         locTopLeft.setAnchorPoint(1, 0);
180         locTopLeft.setPosition(leftWidth, bottomHeight+rescaledHeight);
181 
182         locTopRight.setAnchorPoint(0, 0);
183         locTopRight.setPosition(leftWidth+rescaledWidth, bottomHeight+rescaledHeight);
184 
185         locLeft.setAnchorPoint(1, 0.5);
186         locLeft.setPosition(leftWidth, bottomHeight+rescaledHeight/2 + centerOffset.y);
187         locLeft.setScaleY(verticalScale);
188 
189         locRight.setAnchorPoint(0, 0.5);
190         locRight.setPosition(leftWidth+rescaledWidth,bottomHeight+rescaledHeight/2 + centerOffset.y);
191         locRight.setScaleY(verticalScale);
192 
193         locTop.setAnchorPoint(0.5, 0);
194         locTop.setPosition(leftWidth+rescaledWidth/2 + centerOffset.x,bottomHeight+rescaledHeight);
195         locTop.setScaleX(horizontalScale);
196 
197         locBottom.setAnchorPoint(0.5, 1);
198         locBottom.setPosition(leftWidth+rescaledWidth/2 + centerOffset.x,bottomHeight);
199         locBottom.setScaleX(horizontalScale);
200 
201         locCenter.setAnchorPoint(0.5, 0.5);
202         locCenter.setPosition(leftWidth+rescaledWidth/2 + centerOffset.x, bottomHeight+rescaledHeight/2 + centerOffset.y);
203         locCenter.setScaleX(horizontalScale);
204         locCenter.setScaleY(verticalScale);
205     },
206 
207     /**
208      * Constructor function. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
209      * @function
210      * @param {string|cc.SpriteFrame} file file name of texture or a SpriteFrame
211      * @param {cc.Rect} rect
212      * @param {cc.Rect} capInsets
213      * @returns {Scale9Sprite}
214      */
215     ctor: function (file, rect, capInsets) {
216         cc.Node.prototype.ctor.call(this);
217         this._spriteRect = cc.rect(0, 0, 0, 0);
218         this._capInsetsInternal = cc.rect(0, 0, 0, 0);
219 
220         this._originalSize = cc.size(0, 0);
221         this._preferredSize = cc.size(0, 0);
222         this._capInsets = cc.rect(0, 0, 0, 0);
223         this._renderers = [];
224 
225         if(file != undefined){
226             if(file instanceof cc.SpriteFrame)
227                 this.initWithSpriteFrame(file, rect);
228             else{
229                 var frame = cc.spriteFrameCache.getSpriteFrame(file);
230                 if(frame != null)
231                     this.initWithSpriteFrame(frame, rect);
232                 else
233                     this.initWithFile(file, rect, capInsets);
234             }
235         }else{
236             this.init();
237         }
238     },
239 
240     getSprite: function () {
241         return this._scale9Image;
242     },
243 
244     /** Original sprite's size. */
245     getOriginalSize: function () {
246         return cc.size(this._originalSize);
247     },
248 
249     //if the preferredSize component is given as -1, it is ignored
250     getPreferredSize: function () {
251         return cc.size(this._preferredSize);
252     },
253     _getPreferredWidth: function () {
254         return this._preferredSize.width;
255     },
256     _getPreferredHeight: function () {
257         return this._preferredSize.height;
258     },
259     setPreferredSize: function (preferredSize) {
260         this.setContentSize(preferredSize);
261         this._preferredSize = preferredSize;
262 
263         if (this._positionsAreDirty) {
264             this._updatePositions();
265             this._positionsAreDirty = false;
266             this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
267         }
268     },
269     _setPreferredWidth: function (value) {
270         this._setWidth(value);
271         this._preferredSize.width = value;
272     },
273     _setPreferredHeight: function (value) {
274         this._setHeight(value);
275         this._preferredSize.height = value;
276     },
277 
278     /** Opacity: conforms to CCRGBAProtocol protocol */
279     setOpacity: function (opacity) {
280         cc.Node.prototype.setOpacity.call(this, opacity);
281         if(this._scale9Enabled) {
282             var pChildren = this._renderers;
283             for(var i=0; i<pChildren.length; i++)
284                 pChildren[i].setOpacity(opacity);
285         }
286         else if(this._scale9Image)
287             this._scale9Image.setOpacity(opacity);
288         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
289     },
290 
291     /** Color: conforms to CCRGBAProtocol protocol */
292     setColor: function (color) {
293         cc.Node.prototype.setColor.call(this, color);
294         if(this._scale9Enabled) {
295             var scaleChildren = this._renderers;
296             for (var i = 0; i < scaleChildren.length; i++) {
297                 var selChild = scaleChildren[i];
298                 if (selChild)
299                     selChild.setColor(color);
300             }
301         }
302         else if (this._scale9Image)
303             this._scale9Image.setColor(color);
304         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
305     },
306 
307     getCapInsets: function () {
308         return cc.rect(this._capInsets);
309     },
310 
311     setCapInsets: function (capInsets) {
312         var contentSize = this._contentSize;
313         var tempWidth = contentSize.width, tempHeight = contentSize.height;
314 
315         this.updateWithSprite(  this._scale9Image,
316                                 this._spriteRect,
317                                 this._spriteFrameRotated,
318                                 this._offset,
319                                 this._originalSize,
320                                 capInsets );
321         this._insetLeft = capInsets.x;
322         this._insetTop = capInsets.y;
323         this._insetRight = this._originalSize.width - this._insetLeft - capInsets.width;
324         this._insetBottom = this._originalSize.height - this._insetTop - capInsets.height;
325         //restore the contentSize
326         this.setContentSize(tempWidth, tempHeight);
327     },
328 
329     /**
330      * Gets the left side inset
331      * @returns {number}
332      */
333     getInsetLeft: function () {
334         return this._insetLeft;
335     },
336 
337     /**
338      * Sets the left side inset
339      * @param {Number} insetLeft
340      */
341     setInsetLeft: function (insetLeft) {
342         this._insetLeft = insetLeft;
343         this._updateCapInset();
344     },
345 
346     /**
347      * Gets the top side inset
348      * @returns {number}
349      */
350     getInsetTop: function () {
351         return this._insetTop;
352     },
353 
354     /**
355      * Sets the top side inset
356      * @param {Number} insetTop
357      */
358     setInsetTop: function (insetTop) {
359         this._insetTop = insetTop;
360         this._updateCapInset();
361     },
362 
363     /**
364      * Gets the right side inset
365      * @returns {number}
366      */
367     getInsetRight: function () {
368         return this._insetRight;
369     },
370     /**
371      * Sets the right side inset
372      * @param {Number} insetRight
373      */
374     setInsetRight: function (insetRight) {
375         this._insetRight = insetRight;
376         this._updateCapInset();
377     },
378 
379     /**
380      * Gets the bottom side inset
381      * @returns {number}
382      */
383     getInsetBottom: function () {
384         return this._insetBottom;
385     },
386     /**
387      * Sets the bottom side inset
388      * @param {number} insetBottom
389      */
390     setInsetBottom: function (insetBottom) {
391         this._insetBottom = insetBottom;
392         this._updateCapInset();
393     },
394 
395     /**
396      * Sets the untransformed size of the Scale9Sprite.
397      * @override
398      * @param {cc.Size|Number} size The untransformed size of the Scale9Sprite or The untransformed size's width of the Scale9Sprite.
399      * @param {Number} [height] The untransformed size's height of the Scale9Sprite.
400      */
401     setContentSize: function (size, height) {
402         cc.Node.prototype.setContentSize.call(this, size, height);
403         this._positionsAreDirty = true;
404     },
405 
406     setAnchorPoint: function (point, y) {
407         cc.Node.prototype.setAnchorPoint.call(this, point, y);
408         if(!this._scale9Enabled) {
409             if(this._scale9Image) {
410                 this._scale9Image.setAnchorPoint(point, y);
411                 this._positionsAreDirty = true;
412             }
413         }
414     },
415     _setWidth: function (value) {
416         cc.Node.prototype._setWidth.call(this, value);
417         this._positionsAreDirty = true;
418     },
419 
420     _setHeight: function (value) {
421         cc.Node.prototype._setHeight.call(this, value);
422         this._positionsAreDirty = true;
423     },
424 
425     /**
426      * Initializes a ccui.Scale9Sprite. please do not call this function by yourself, you should pass the parameters to constructor to initialize it.
427      * @returns {boolean}
428      */
429     init: function () {
430         return this.initWithBatchNode(null, cc.rect(0, 0, 0, 0), false, cc.rect(0, 0, 0, 0));
431     },
432 
433     /**
434      * Initializes a 9-slice sprite with a SpriteBatchNode.
435      * @param {cc.SpriteBatchNode} batchNode
436      * @param {cc.Rect} rect
437      * @param {boolean|cc.Rect} rotated
438      * @param {cc.Rect} [capInsets]
439      * @returns {boolean}
440      */
441     initWithBatchNode: function (batchNode, rect, rotated, capInsets) {
442         if (capInsets === undefined) {
443             capInsets = rotated;
444             rotated = false;
445         }
446 
447         if (batchNode)
448             this.updateWithBatchNode(batchNode, rect, rotated, capInsets);
449 
450         this.setCascadeColorEnabled(true);
451         this.setCascadeOpacityEnabled(true);
452         this.setAnchorPoint(0.5, 0.5);
453         this._positionsAreDirty = true;
454         return true;
455     },
456 
457     /**
458      * Initializes a 9-slice sprite with a texture file, a delimitation zone and
459      * with the specified cap insets.
460      * Once the sprite is created, you can then call its "setContentSize:" method
461      * to resize the sprite will all it's 9-slice goodness intact.
462      * It respects the anchorPoint too.
463      *
464      * @param {String} file The name of the texture file.
465      * @param {cc.Rect} rect The rectangle that describes the sub-part of the texture that
466      * is the whole image. If the shape is the whole texture, set this to the texture's full rect.
467      * @param {cc.Rect} capInsets The values to use for the cap insets.
468      */
469     initWithFile: function (file, rect, capInsets) {
470         if (file instanceof cc.Rect) {
471             file = arguments[1];
472             capInsets = arguments[0];
473             rect = cc.rect(0, 0, 0, 0);
474         } else {
475             rect = rect || cc.rect(0, 0, 0, 0);
476             capInsets = capInsets || cc.rect(0, 0, 0, 0);
477         }
478 
479         if(!file)
480             throw new Error("ccui.Scale9Sprite.initWithFile(): file should be non-null");
481 
482         var texture = cc.textureCache.getTextureForKey(file);
483         if (!texture) {
484             texture = cc.textureCache.addImage(file);
485         }
486 
487         var locLoaded = texture.isLoaded();
488         this._textureLoaded = locLoaded;
489         if(!locLoaded){
490             texture.addEventListener("load", function(sender){
491                 // the texture is rotated on Canvas render mode, so isRotated always is false.
492                 var preferredSize = this._preferredSize, restorePreferredSize = preferredSize.width !== 0 && preferredSize.height !== 0;
493                 if (restorePreferredSize) preferredSize = cc.size(preferredSize.width, preferredSize.height);
494                 var size  = sender.getContentSize();
495                 this.updateWithBatchNode(this._scale9Image, cc.rect(0,0,size.width,size.height), false, this._capInsets);
496                 if (restorePreferredSize)this.setPreferredSize(preferredSize);
497                 this._positionsAreDirty = true;
498                 this.setNodeDirty();
499                 this.dispatchEvent("load");
500             }, this);
501         }
502 
503         return this.initWithBatchNode(new cc.SpriteBatchNode(file, 9), rect, false, capInsets);
504     },
505 
506     /**
507      * Initializes a 9-slice sprite with an sprite frame and with the specified
508      * cap insets.
509      * Once the sprite is created, you can then call its "setContentSize:" method
510      * to resize the sprite will all it's 9-slice goodness interact.
511      * It respects the anchorPoint too.
512      *
513      * @param spriteFrame The sprite frame object.
514      * @param capInsets The values to use for the cap insets.
515      */
516     initWithSpriteFrame: function (spriteFrame, capInsets) {
517         if(!spriteFrame || !spriteFrame.getTexture())
518             throw new Error("ccui.Scale9Sprite.initWithSpriteFrame(): spriteFrame should be non-null and its texture should be non-null");
519 
520         capInsets = capInsets || cc.rect(0, 0, 0, 0);
521         var locLoaded = spriteFrame.textureLoaded();
522         this._textureLoaded = locLoaded;
523         if(!locLoaded){
524             spriteFrame.addEventListener("load", function(sender){
525                 // the texture is rotated on Canvas render mode, so isRotated always is false.
526                 var preferredSize = this._preferredSize, restorePreferredSize = preferredSize.width !== 0 && preferredSize.height !== 0;
527                 if (restorePreferredSize) preferredSize = cc.size(preferredSize.width, preferredSize.height);
528                 this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType === cc.game.RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets);
529                 if (restorePreferredSize)this.setPreferredSize(preferredSize);
530                 this._positionsAreDirty = true;
531                 this.setNodeDirty();
532                 this.dispatchEvent("load");
533             },this);
534         }
535         var batchNode = new cc.SpriteBatchNode(spriteFrame.getTexture(), 9);
536         // the texture is rotated on Canvas render mode, so isRotated always is false.
537         return this.initWithBatchNode(batchNode, spriteFrame.getRect(), cc._renderType === cc.game.RENDER_TYPE_WEBGL && spriteFrame.isRotated(), capInsets);
538     },
539 
540     /**
541      * Initializes a 9-slice sprite with an sprite frame name and with the specified
542      * cap insets.
543      * Once the sprite is created, you can then call its "setContentSize:" method
544      * to resize the sprite will all it's 9-slice goodness interact.
545      * It respects the anchorPoint too.
546      *
547      * @param spriteFrameName The sprite frame name.
548      * @param capInsets The values to use for the cap insets.
549      */
550     initWithSpriteFrameName: function (spriteFrameName, capInsets) {
551         if(!spriteFrameName)
552             throw new Error("ccui.Scale9Sprite.initWithSpriteFrameName(): spriteFrameName should be non-null");
553         capInsets = capInsets || cc.rect(0, 0, 0, 0);
554 
555         var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName);
556         if (frame == null) {
557             cc.log("ccui.Scale9Sprite.initWithSpriteFrameName(): can't find the sprite frame by spriteFrameName");
558             return false;
559         }
560 
561         return this.initWithSpriteFrame(frame, capInsets);
562     },
563 
564     /**
565      * Creates and returns a new sprite object with the specified cap insets.
566      * You use this method to add cap insets to a sprite or to change the existing
567      * cap insets of a sprite. In both cases, you get back a new image and the
568      * original sprite remains untouched.
569      *
570      * @param {cc.Rect} capInsets The values to use for the cap insets.
571      */
572     resizableSpriteWithCapInsets: function (capInsets) {
573         var pReturn = new ccui.Scale9Sprite();
574         if (pReturn && pReturn.initWithBatchNode(this._scale9Image, this._spriteRect, false, capInsets))
575             return pReturn;
576         return null;
577     },
578 
579     /** sets the premultipliedAlphaOpacity property.
580      If set to NO then opacity will be applied as: glColor(R,G,B,opacity);
581      If set to YES then opacity will be applied as: glColor(opacity, opacity, opacity, opacity );
582      Textures with premultiplied alpha will have this property by default on YES. Otherwise the default value is NO
583      @since v0.8
584      */
585     setOpacityModifyRGB: function (value) {
586         if(!this._scale9Image)
587             return;
588         this._opacityModifyRGB = value;
589         var scaleChildren = this._scale9Image.getChildren();
590         if (scaleChildren) {
591             for (var i = 0, len = scaleChildren.length; i < len; i++)
592                 scaleChildren[i].setOpacityModifyRGB(value);
593         }
594         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
595     },
596 
597     /** returns whether or not the opacity will be applied using glColor(R,G,B,opacity) or glColor(opacity, opacity, opacity, opacity);
598      @since v0.8
599      */
600     isOpacityModifyRGB: function () {
601         return this._opacityModifyRGB;
602     },
603 
604     createSlicedSprites: function() {
605         var width = this._originalSize.width,
606             height = this._originalSize.height;
607         var originalRect = this._spriteRect;
608         var offsetX = Math.floor(this._offset.x + (width - originalRect.width) / 2.0);
609         var offsetY = Math.floor(this._offset.y + (height - originalRect.height) / 2.0);
610         var sx = originalRect.x,
611             sy = originalRect.y;
612         var capInsetsInternal = this._capInsetsInternal;
613         var locScale9Image = this._scale9Image;
614         var selTexture = locScale9Image.getTexture();
615         var rotated = this._spriteFrameRotated;
616         var rect = cc.rect(originalRect.x, originalRect.y, originalRect.width, originalRect.height);
617 
618         if(cc._rectEqualToZero(capInsetsInternal))
619             capInsetsInternal = cc.rect(width /3, height /3, width /3, height /3);
620 
621         if(this._spriteFrameRotated) {
622             sx -= offsetY;  sy -= offsetX;
623         }else{
624             sx -= offsetX;  sy -= offsetY;
625         }
626         originalRect = cc.rect(sx, sy, width, height);
627 
628         var leftWidth = capInsetsInternal.x,
629             centerWidth = capInsetsInternal.width,
630             rightWidth = originalRect.width - (leftWidth + centerWidth),
631             topHeight = capInsetsInternal.y,
632             centerHeight = capInsetsInternal.height,
633             bottomHeight = originalRect.height - (topHeight + centerHeight);
634 
635 
636         var x = 0.0, y = 0.0;
637 
638         // top left
639         var leftTopBoundsOriginal = cc.rect(x + 0.5 | 0, y + 0.5 | 0, leftWidth + 0.5 | 0, topHeight + 0.5 | 0);
640         var leftTopBounds = leftTopBoundsOriginal;
641 
642         // top center
643         x += leftWidth;
644         var centerTopBoundsOriginal = cc.rect(x + 0.5 | 0, y + 0.5 | 0, centerWidth + 0.5 | 0, topHeight + 0.5 | 0);
645         var centerTopBounds = centerTopBoundsOriginal;
646 
647         // top right
648         x += centerWidth;
649         var  rightTopBoundsOriginal = cc.rect(x + 0.5 | 0, y + 0.5 | 0, rightWidth + 0.5 | 0, topHeight + 0.5 | 0);
650         var  rightTopBounds = rightTopBoundsOriginal;
651 
652         // ... center row
653         x = 0.0;
654         y = 0.0;
655         y += topHeight;
656 
657         // center left
658         var leftCenterBounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, leftWidth + 0.5 | 0, centerHeight + 0.5 | 0);
659 
660         // center center
661         x += leftWidth;
662         var centerBoundsOriginal = cc.rect(x + 0.5 | 0, y + 0.5 | 0, centerWidth + 0.5 | 0, centerHeight + 0.5 | 0);
663         var centerBounds = centerBoundsOriginal;
664 
665         // center right
666         x += centerWidth;
667         var rightCenterBounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, rightWidth + 0.5 | 0, centerHeight + 0.5 | 0);
668 
669         // ... bottom row
670         x = 0.0;
671         y = 0.0;
672         y += topHeight;
673         y += centerHeight;
674 
675         // bottom left
676         var leftBottomBounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, leftWidth + 0.5 | 0, bottomHeight + 0.5 | 0);
677 
678         // bottom center
679         x += leftWidth;
680         var centerBottomBounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, centerWidth + 0.5 | 0, bottomHeight + 0.5 | 0);
681 
682         // bottom right
683         x += centerWidth;
684         var rightBottomBoundsOriginal = cc.rect(x + 0.5 | 0, y + 0.5 | 0, rightWidth + 0.5 | 0, bottomHeight + 0.5 | 0);
685         var rightBottomBounds = rightBottomBoundsOriginal;
686 
687         var rotatedLeftTopBoundsOriginal = leftTopBoundsOriginal;
688         var rotatedCenterBoundsOriginal = centerBoundsOriginal;
689         var rotatedRightBottomBoundsOriginal = rightBottomBoundsOriginal;
690 
691         var rotatedCenterBounds = centerBounds;
692         var rotatedRightBottomBounds = rightBottomBounds;
693         var rotatedLeftBottomBounds = leftBottomBounds;
694         var rotatedRightTopBounds = rightTopBounds;
695         var rotatedLeftTopBounds = leftTopBounds;
696         var rotatedRightCenterBounds = rightCenterBounds;
697         var rotatedLeftCenterBounds = leftCenterBounds;
698         var rotatedCenterBottomBounds = centerBottomBounds;
699         var rotatedCenterTopBounds = centerTopBounds;
700 
701         var t = cc.affineTransformMakeIdentity();
702         if (!rotated) {
703             t = cc.affineTransformTranslate(t, rect.x, rect.y);
704         
705             rotatedLeftTopBoundsOriginal = cc.rectApplyAffineTransform(rotatedLeftTopBoundsOriginal, t);
706             rotatedCenterBoundsOriginal = cc.rectApplyAffineTransform(rotatedCenterBoundsOriginal, t);
707             rotatedRightBottomBoundsOriginal = cc.rectApplyAffineTransform(rotatedRightBottomBoundsOriginal, t);
708         
709             rotatedCenterBounds = cc.rectApplyAffineTransform(rotatedCenterBounds, t);
710             rotatedRightBottomBounds = cc.rectApplyAffineTransform(rotatedRightBottomBounds, t);
711             rotatedLeftBottomBounds = cc.rectApplyAffineTransform(rotatedLeftBottomBounds, t);
712             rotatedRightTopBounds = cc.rectApplyAffineTransform(rotatedRightTopBounds, t);
713             rotatedLeftTopBounds = cc.rectApplyAffineTransform(rotatedLeftTopBounds, t);
714             rotatedRightCenterBounds = cc.rectApplyAffineTransform(rotatedRightCenterBounds, t);
715             rotatedLeftCenterBounds = cc.rectApplyAffineTransform(rotatedLeftCenterBounds, t);
716             rotatedCenterBottomBounds = cc.rectApplyAffineTransform(rotatedCenterBottomBounds, t);
717             rotatedCenterTopBounds = cc.rectApplyAffineTransform(rotatedCenterTopBounds, t);
718 
719         } else {
720             t = cc.affineTransformTranslate(t, rect.height + rect.x, rect.y);
721             t = cc.affineTransformRotate(t, 1.57079633);
722         
723             leftTopBoundsOriginal = cc.rectApplyAffineTransform(leftTopBoundsOriginal, t);
724             centerBoundsOriginal = cc.rectApplyAffineTransform(centerBoundsOriginal, t);
725             rightBottomBoundsOriginal = cc.rectApplyAffineTransform(rightBottomBoundsOriginal, t);
726         
727             centerBounds = cc.rectApplyAffineTransform(centerBounds, t);
728             rightBottomBounds = cc.rectApplyAffineTransform(rightBottomBounds, t);
729             leftBottomBounds = cc.rectApplyAffineTransform(leftBottomBounds, t);
730             rightTopBounds = cc.rectApplyAffineTransform(rightTopBounds, t);
731             leftTopBounds = cc.rectApplyAffineTransform(leftTopBounds, t);
732             rightCenterBounds = cc.rectApplyAffineTransform(rightCenterBounds, t);
733             leftCenterBounds = cc.rectApplyAffineTransform(leftCenterBounds, t);
734             centerBottomBounds = cc.rectApplyAffineTransform(centerBottomBounds, t);
735             centerTopBounds = cc.rectApplyAffineTransform(centerTopBounds, t);
736         
737             rotatedLeftTopBoundsOriginal.x = leftTopBoundsOriginal.x;
738             rotatedCenterBoundsOriginal.x = centerBoundsOriginal.x;
739             rotatedRightBottomBoundsOriginal.x = rightBottomBoundsOriginal.x;
740         
741             rotatedCenterBounds.x = centerBounds.x;
742             rotatedRightBottomBounds.x = rightBottomBounds.x;
743             rotatedLeftBottomBounds.x = leftBottomBounds.x;
744             rotatedRightTopBounds.x = rightTopBounds.x;
745             rotatedLeftTopBounds.x = leftTopBounds.x;
746             rotatedRightCenterBounds.x = rightCenterBounds.x;
747             rotatedLeftCenterBounds.x = leftCenterBounds.x;
748             rotatedCenterBottomBounds.x = centerBottomBounds.x;
749             rotatedCenterTopBounds.x = centerTopBounds.x;
750         
751         
752             rotatedLeftTopBoundsOriginal.y = leftTopBoundsOriginal.y;
753             rotatedCenterBoundsOriginal.y = centerBoundsOriginal.y;
754             rotatedRightBottomBoundsOriginal.y = rightBottomBoundsOriginal.y;
755         
756             rotatedCenterBounds.y = centerBounds.y;
757             rotatedRightBottomBounds.y = rightBottomBounds.y;
758             rotatedLeftBottomBounds.y = leftBottomBounds.y;
759             rotatedRightTopBounds.y = rightTopBounds.y;
760             rotatedLeftTopBounds.y = leftTopBounds.y;
761             rotatedRightCenterBounds.y = rightCenterBounds.y;
762             rotatedLeftCenterBounds.y = leftCenterBounds.y;
763             rotatedCenterBottomBounds.y = centerBottomBounds.y;
764             rotatedCenterTopBounds.y = centerTopBounds.y;
765         }
766 
767         // Centre
768         if(!this._centre)
769             this._centre = new cc.Sprite();
770         this._centre.initWithTexture(selTexture, rotatedCenterBounds, rotated);
771         if(rotatedCenterBounds.width > 0 && rotatedCenterBounds.height > 0 )
772             this._renderers.push(this._centre);
773 
774         // Top
775         if(!this._top)
776             this._top = new cc.Sprite();
777         this._top.initWithTexture(selTexture, rotatedCenterTopBounds, rotated);
778         if(rotatedCenterTopBounds.width > 0 && rotatedCenterTopBounds.height > 0 )
779             this._renderers.push(this._top);
780 
781         // Bottom
782         if(!this._bottom)
783             this._bottom = new cc.Sprite();
784         this._bottom.initWithTexture(selTexture, rotatedCenterBottomBounds, rotated);
785         if(rotatedCenterBottomBounds.width > 0 && rotatedCenterBottomBounds.height > 0 )
786             this._renderers.push(this._bottom);
787 
788         // Left
789         if(!this._left)
790             this._left = new cc.Sprite();
791         this._left.initWithTexture(selTexture, rotatedLeftCenterBounds, rotated);
792         if(rotatedLeftCenterBounds.width > 0 && rotatedLeftCenterBounds.height > 0 )
793             this._renderers.push(this._left);
794 
795         // Right
796         if(!this._right)
797             this._right = new cc.Sprite();
798         this._right.initWithTexture(selTexture, rotatedRightCenterBounds, rotated);
799         if(rotatedRightCenterBounds.width > 0 && rotatedRightCenterBounds.height > 0 )
800             this._renderers.push(this._right);
801 
802         // Top left
803         if(!this._topLeft)
804             this._topLeft = new cc.Sprite();
805         this._topLeft.initWithTexture(selTexture, rotatedLeftTopBounds, rotated);
806         if(rotatedLeftTopBounds.width > 0 && rotatedLeftTopBounds.height > 0 )
807             this._renderers.push(this._topLeft);
808 
809         // Top right
810         if(!this._topRight)
811             this._topRight = new cc.Sprite();
812         this._topRight.initWithTexture(selTexture, rotatedRightTopBounds, rotated);
813         if(rotatedRightTopBounds.width > 0 && rotatedRightTopBounds.height > 0 )
814             this._renderers.push(this._topRight);
815 
816         // Bottom left
817         if(!this._bottomLeft)
818             this._bottomLeft = new cc.Sprite();
819         this._bottomLeft.initWithTexture(selTexture, rotatedLeftBottomBounds, rotated);
820         if(rotatedLeftBottomBounds.width > 0 && rotatedLeftBottomBounds.height > 0 )
821             this._renderers.push(this._bottomLeft);
822 
823         // Bottom right
824         if(!this._bottomRight)
825             this._bottomRight = new cc.Sprite();
826         this._bottomRight.initWithTexture(selTexture, rotatedRightBottomBounds, rotated);
827         if(rotatedRightBottomBounds.width > 0 && rotatedRightBottomBounds.height > 0 )
828             this._renderers.push(this._bottomRight);
829     },
830     /**
831      * @brief Update Scale9Sprite with a specified sprite.
832      *
833      * @param sprite A sprite pointer.
834      * @param rect A delimitation zone.
835      * @param rotated Whether the sprite is rotated or not.
836      * @param offset The offset when slice the sprite.
837      * @param originalSize The origial size of the sprite.
838      * @param capInsets The Values to use for the cap insets.
839      * @return True if update success, false otherwise.
840      */
841     updateWithSprite: function(sprite, spriteRect, spriteFrameRotated, offset, originalSize, capInsets) {
842         var opacity = this.getOpacity();
843         var color = this.getColor();
844         this._renderers.length = 0;
845         if(sprite) {
846             if(!sprite.getSpriteFrame())
847                 return false;
848             if(!this._scale9Image)
849                 this._scale9Image = sprite;
850         }
851         if(!this._scale9Image)  return false;
852         var rect = spriteRect;
853         var size = originalSize;
854 
855         var tmpTexture = this._scale9Image.getTexture();
856         var locLoaded = tmpTexture && tmpTexture.isLoaded();
857         this._textureLoaded = locLoaded;
858         if(!locLoaded){
859             tmpTexture.addEventListener("load", function(sender){
860                 this._positionsAreDirty = true;
861                 this.updateWithSprite(sprite, spriteRect, spriteFrameRotated, offset, originalSize, capInsets);
862                 this.setVisible(true);
863                 this.setNodeDirty();
864                 this.dispatchEvent("load");
865             }, this);
866             this.setVisible(false);
867             return true;
868         }
869         if(cc._rectEqualToZero(rect)) {
870             var textureSize = tmpTexture.getContentSize();
871             rect = cc.rect(0, 0, textureSize.width, textureSize.height);
872         }
873         if(size.width === 0 && size.height === 0)
874             size = cc.size(rect.width, rect.height);
875         this._capInsets = capInsets;
876         this._spriteRect = rect;
877         this._offset = offset;
878         this._spriteFrameRotated = spriteFrameRotated;
879         this._originalSize = size;
880         this._preferredSize = size;
881         this._capInsetsInternal = capInsets;
882         if(this._scale9Enabled)
883             this.createSlicedSprites();
884         else
885             this._scale9Image.initWithTexture(tmpTexture, this._spriteRect, this._spriteFrameRotated);
886 
887         this.setState(this._brightState);
888         this.setContentSize(size);
889         if(this._spritesGenerated === true) {
890             this.setOpacity(opacity);
891             this.setColor(color);
892         }
893         this._spritesGenerated = true;
894         return true;
895     },
896     /**
897      * Update the scale9Sprite with a SpriteBatchNode.
898      * @param {cc.SpriteBatchNode} batchNode
899      * @param {cc.Rect} originalRect
900      * @param {boolean} rotated
901      * @param {cc.Rect} capInsets
902      * @returns {boolean}
903      */
904     updateWithBatchNode: function (batchNode, originalRect, rotated, capInsets) {
905         var sprite = new cc.Sprite(batchNode.getTexture());
906         var pos = cc.p(0,0);
907         var originalSize = cc.size(originalRect.width,originalRect.height);
908 
909         var tmpTexture = batchNode.getTexture();
910         var locLoaded = tmpTexture.isLoaded();
911         this._textureLoaded = locLoaded;
912         if(!locLoaded){
913             tmpTexture.addEventListener("load", function(sender){
914                 this._positionsAreDirty = true;
915                 this.updateWithBatchNode(batchNode, originalRect, rotated, capInsets);
916                 this.setVisible(true);
917                 this.setNodeDirty();
918                 this.dispatchEvent("load");
919             }, this);
920             this.setVisible(false);
921             return true;
922         }
923         return this.updateWithSprite(sprite, originalRect, rotated, pos, originalSize, capInsets);
924     },
925 
926     /**
927      * set the sprite frame of ccui.Scale9Sprite
928      * @param {cc.SpriteFrame} spriteFrame
929      * @param {cc.rect} capInsets
930      */
931     setSpriteFrame: function (spriteFrame, capInsets) {
932         // Reset insets
933         if (!capInsets)
934             capInsets = cc.rect();
935         var sprite = new cc.Sprite(spriteFrame.getTexture());
936         var locLoaded = spriteFrame.textureLoaded();
937         this._textureLoaded = locLoaded;
938         if(!locLoaded){
939             spriteFrame.addEventListener("load", function(sender){
940                 // the texture is rotated on Canvas render mode, so isRotated always is false.
941                 var preferredSize = this._preferredSize, restorePreferredSize = preferredSize.width !== 0 && preferredSize.height !== 0;
942                 if (restorePreferredSize) preferredSize = cc.size(preferredSize.width, preferredSize.height);
943                 this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType === cc.game.RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets);
944                 if (restorePreferredSize)this.setPreferredSize(preferredSize);
945                 this._positionsAreDirty = true;
946                 this.setNodeDirty();
947                 this.dispatchEvent("load");
948             },this);
949         }
950         this.updateWithSprite(sprite, spriteFrame.getRect(),spriteFrame.isRotated(),spriteFrame.getOffset(),spriteFrame.getOriginalSize(),capInsets);
951 
952         this._insetLeft = capInsets.x;
953         this._insetTop = capInsets.y;
954         this._insetRight = this._originalSize.width - this._insetLeft - capInsets.width;
955         this._insetBottom = this._originalSize.height - this._insetTop - capInsets.height;
956     },
957 
958     //v3.3
959     /**
960      * Sets ccui.Scale9Sprite's state
961      * @since v3.3
962      * @param {Number} state
963      */
964     setState: function(state){
965         this._renderCmd.setState(state);
966     },
967     /**
968      * @brief Toggle 9-slice feature.
969      * If Scale9Sprite is 9-slice disabled, the Scale9Sprite will rendered as a normal sprite.
970      * @param {boolean}    enabled    True to enable 9-slice, false otherwise.
971      */
972     setScale9Enabled: function(enabled){
973         if (this._scale9Enabled === enabled)
974         {
975             return;
976         }
977         this._scale9Enabled = enabled;
978         this._renderers.length = 0;
979         //we must invalide the transform when toggling scale9enabled
980         cc.Node.transformDirty = true;
981         if (this._scale9Enabled) {
982             if (this._scale9Image) {
983                 this.updateWithSprite(this._scale9Image,
984                     this._spriteRect,
985                     this._spriteFrameRotated,
986                     this._offset,
987                     this._originalSize,
988                     this._capInsets);
989             }
990         }
991         this._positionsAreDirty = true;
992     },
993 
994     _setRenderersPosition: function() {
995         if(this._positionsAreDirty) {
996             this._updatePositions();
997             this._adjustScale9ImagePosition();
998             this._positionsAreDirty = false;
999         }
1000     },
1001 
1002     _adjustScale9ImagePosition: function() {
1003         var image = this._scale9Image;
1004         var contentSize = this._contentSize;
1005         if(image) {
1006             image.x = contentSize.width * image.getAnchorPoint().x;
1007             image.y = contentSize.height * image.getAnchorPoint().y;
1008         }
1009     },
1010 
1011     _adjustScale9ImageScale: function() {
1012         var image = this._scale9Image;
1013         var contentSize = this._contentSize;
1014         if(image) {
1015             image.setScale(contentSize.width/image.width, contentSize.height/image.height);
1016         }
1017     },
1018 
1019     /**
1020      * Sets whether the widget should be flipped horizontally or not.
1021      * @since v3.3
1022      * @param flippedX true if the widget should be flipped horizontally, false otherwise.
1023      */
1024     setFlippedX: function(flippedX){
1025         var realScale = this.getScaleX();
1026         this._flippedX = flippedX;
1027         this.setScaleX(realScale);
1028         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
1029     },
1030 
1031     /**
1032      * <p>
1033      * Returns the flag which indicates whether the widget is flipped horizontally or not.                         <br/>
1034      *                                                                                                             <br/>
1035      * It only flips the texture of the widget, and not the texture of the widget's children.                      <br/>
1036      * Also, flipping the texture doesn't alter the anchorPoint.                                                   <br/>
1037      * If you want to flip the anchorPoint too, and/or to flip the children too use:                               <br/>
1038      * widget->setScaleX(sprite->getScaleX() * -1);                                                                <br/>
1039      * </p>
1040      * @since v3.3
1041      * @return {Boolean} true if the widget is flipped horizontally, false otherwise.
1042      */
1043     isFlippedX: function(){
1044         return this._flippedX;
1045     },
1046 
1047     /**
1048      * Sets whether the widget should be flipped vertically or not.
1049      * @since v3.3
1050      * @param flippedY true if the widget should be flipped vertically, false otherwise.
1051      */
1052     setFlippedY:function(flippedY){
1053         var realScale = this.getScaleY();
1054         this._flippedY = flippedY;
1055         this.setScaleY(realScale);
1056         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
1057     },
1058 
1059     /**
1060      * <p>
1061      * Return the flag which indicates whether the widget is flipped vertically or not.                             <br/>
1062      *                                                                                                              <br/>
1063      * It only flips the texture of the widget, and not the texture of the widget's children.                       <br/>
1064      * Also, flipping the texture doesn't alter the anchorPoint.                                                    <br/>
1065      * If you want to flip the anchorPoint too, and/or to flip the children too use:                                <br/>
1066      * widget->setScaleY(widget->getScaleY() * -1);                                                                 <br/>
1067      * </p>
1068      * @since v3.3
1069      * @return {Boolean} true if the widget is flipped vertically, false otherwise.
1070      */
1071     isFlippedY:function(){
1072         return this._flippedY;
1073     },
1074 
1075     setScaleX: function (scaleX) {
1076         if (this._flippedX)
1077             scaleX = scaleX * -1;
1078         cc.Node.prototype.setScaleX.call(this, scaleX);
1079         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
1080     },
1081 
1082     setScaleY: function (scaleY) {
1083         if (this._flippedY)
1084             scaleY = scaleY * -1;
1085         cc.Node.prototype.setScaleY.call(this, scaleY);
1086         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.cacheDirty);
1087     },
1088 
1089     setScale: function (scaleX, scaleY) {
1090         if(scaleY === undefined)
1091             scaleY = scaleX;
1092         this.setScaleX(scaleX);
1093         this.setScaleY(scaleY);
1094     },
1095 
1096     getScaleX: function () {
1097         var originalScale = cc.Node.prototype.getScaleX.call(this);
1098         if (this._flippedX)
1099             originalScale = originalScale * -1.0;
1100         return originalScale;
1101     },
1102 
1103     getScaleY: function () {
1104         var originalScale = cc.Node.prototype.getScaleY.call(this);
1105         if (this._flippedY)
1106             originalScale = originalScale * -1.0;
1107         return originalScale;
1108     },
1109 
1110     getScale: function () {
1111         if(this.getScaleX() !== this.getScaleY())
1112             cc.log("Scale9Sprite#scale. ScaleX != ScaleY. Don't know which one to return");
1113         return this.getScaleX();
1114     },
1115 
1116     _createRenderCmd: function(){
1117         if(cc._renderType === cc.game.RENDER_TYPE_CANVAS)
1118             return new ccui.Scale9Sprite.CanvasRenderCmd(this);
1119         else
1120             return new ccui.Scale9Sprite.WebGLRenderCmd(this);
1121     }
1122 });
1123 
1124 var _p = ccui.Scale9Sprite.prototype;
1125 cc.EventHelper.prototype.apply(_p);
1126 
1127 // Extended properties
1128 /** @expose */
1129 _p.preferredSize;
1130 cc.defineGetterSetter(_p, "preferredSize", _p.getPreferredSize, _p.setPreferredSize);
1131 /** @expose */
1132 _p.capInsets;
1133 cc.defineGetterSetter(_p, "capInsets", _p.getCapInsets, _p.setCapInsets);
1134 /** @expose */
1135 _p.insetLeft;
1136 cc.defineGetterSetter(_p, "insetLeft", _p.getInsetLeft, _p.setInsetLeft);
1137 /** @expose */
1138 _p.insetTop;
1139 cc.defineGetterSetter(_p, "insetTop", _p.getInsetTop, _p.setInsetTop);
1140 /** @expose */
1141 _p.insetRight;
1142 cc.defineGetterSetter(_p, "insetRight", _p.getInsetRight, _p.setInsetRight);
1143 /** @expose */
1144 _p.insetBottom;
1145 cc.defineGetterSetter(_p, "insetBottom", _p.getInsetBottom, _p.setInsetBottom);
1146 
1147 _p = null;
1148 
1149 /**
1150  * Creates a 9-slice sprite with a texture file, a delimitation zone and
1151  * with the specified cap insets.
1152  * @deprecated since v3.0, please use new ccui.Scale9Sprite(file, rect, capInsets) instead.
1153  * @param {String|cc.SpriteFrame} file file name of texture or a cc.Sprite object
1154  * @param {cc.Rect} rect the rect of the texture
1155  * @param {cc.Rect} capInsets the cap insets of ccui.Scale9Sprite
1156  * @returns {ccui.Scale9Sprite}
1157  */
1158 ccui.Scale9Sprite.create = function (file, rect, capInsets) {
1159     return new ccui.Scale9Sprite(file, rect, capInsets);
1160 };
1161 
1162 /**
1163  * create a ccui.Scale9Sprite with Sprite frame.
1164  * @deprecated since v3.0, please use "new ccui.Scale9Sprite(spriteFrame, capInsets)" instead.
1165  * @param {cc.SpriteFrame} spriteFrame
1166  * @param {cc.Rect} capInsets
1167  * @returns {ccui.Scale9Sprite}
1168  */
1169 ccui.Scale9Sprite.createWithSpriteFrame = function (spriteFrame, capInsets) {
1170     return new ccui.Scale9Sprite(spriteFrame, capInsets);
1171 };
1172 
1173 /**
1174  * create a ccui.Scale9Sprite with a Sprite frame name
1175  * @deprecated since v3.0, please use "new ccui.Scale9Sprite(spriteFrameName, capInsets)" instead.
1176  * @param {string} spriteFrameName
1177  * @param {cc.Rect} capInsets
1178  * @returns {Scale9Sprite}
1179  */
1180 ccui.Scale9Sprite.createWithSpriteFrameName = function (spriteFrameName, capInsets) {
1181     return new ccui.Scale9Sprite(spriteFrameName, capInsets);
1182 };
1183 
1184 /**
1185  * @ignore
1186  */
1187 ccui.Scale9Sprite.POSITIONS_CENTRE = 0;
1188 ccui.Scale9Sprite.POSITIONS_TOP = 1;
1189 ccui.Scale9Sprite.POSITIONS_LEFT = 2;
1190 ccui.Scale9Sprite.POSITIONS_RIGHT = 3;
1191 ccui.Scale9Sprite.POSITIONS_BOTTOM = 4;
1192 ccui.Scale9Sprite.POSITIONS_TOPRIGHT = 5;
1193 ccui.Scale9Sprite.POSITIONS_TOPLEFT = 6;
1194 ccui.Scale9Sprite.POSITIONS_BOTTOMRIGHT = 7;
1195 
1196 ccui.Scale9Sprite.state = {NORMAL: 0, GRAY: 1};
1197