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