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 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 cc._globalFontSize = cc.ITEM_SIZE;
 28 cc._globalFontName = "Arial";
 29 cc._globalFontNameRelease = false;
 30 
 31 /**
 32  * Subclass cc.MenuItem (or any subclass) to create your custom cc.MenuItem objects.
 33  * @class
 34  * @extends cc.Node
 35  * @param {function|String} callback
 36  * @param  {cc.Node} target
 37  */
 38 cc.MenuItem = cc.Node.extend(/** @lends cc.MenuItem# */{
 39     _enabled: false,
 40     _target: null,
 41     _callback: null,
 42     _isSelected: false,
 43     _className: "MenuItem",
 44 
 45     /**
 46      * Constructor of cc.MenuItem
 47      * @param {function|String} callback
 48      * @param {cc.Node} target
 49      */
 50     ctor: function (callback, target) {
 51         var nodeP = cc.Node.prototype;
 52         nodeP.ctor.call(this);
 53         this._target = null;
 54         this._callback = null;
 55         this._isSelected = false;
 56         this._enabled = false;
 57 
 58         nodeP.setAnchorPoint.call(this, 0.5, 0.5);
 59         this._target = target || null;
 60         this._callback = callback || null;
 61         if (this._callback) {
 62             this._enabled = true;
 63         }
 64     },
 65 
 66     /**
 67      * return whether MenuItem is selected
 68      * @return {Boolean}
 69      */
 70     isSelected: function () {
 71         return this._isSelected;
 72     },
 73     /**
 74      * only use for jsbinding
 75      * @param value
 76      */
 77     setOpacityModifyRGB: function (value) {
 78     },
 79     /**
 80      * only use for jsbinding
 81      * @returns {boolean}
 82      */
 83     isOpacityModifyRGB: function () {
 84         return false;
 85     },
 86 
 87     /**
 88      * set the target/selector of the menu item
 89      * @param {function|String} selector
 90      * @param {cc.Node} rec
 91      * @deprecated since v3.0
 92      */
 93     setTarget: function (selector, rec) {
 94         this._target = rec;
 95         this._callback = selector;
 96     },
 97 
 98     /**
 99      * return whether MenuItem is Enabled
100      * @return {Boolean}
101      */
102     isEnabled: function () {
103         return this._enabled;
104     },
105 
106     /**
107      * set enable value of MenuItem
108      * @param {Boolean} enable
109      */
110     setEnabled: function (enable) {
111         this._enabled = enable;
112     },
113 
114     /**
115      * initializes a cc.MenuItem with callback
116      * @param {function|String} callback
117      * @param {cc.Node} target
118      * @return {Boolean}
119      */
120     initWithCallback: function (callback, target) {
121         this.anchorX = 0.5;
122         this.anchorY = 0.5;
123         this._target = target;
124         this._callback = callback;
125         this._enabled = true;
126         this._isSelected = false;
127         return true;
128     },
129 
130     /**
131      * return rect value of cc.MenuItem
132      * @return {cc.Rect}
133      */
134     rect: function () {
135         var locPosition = this._position, locContentSize = this._contentSize, locAnchorPoint = this._anchorPoint;
136         return cc.rect(locPosition.x - locContentSize.width * locAnchorPoint.x,
137             locPosition.y - locContentSize.height * locAnchorPoint.y,
138             locContentSize.width, locContentSize.height);
139     },
140 
141     /**
142      * set the cc.MenuItem selected same as setIsSelected(true)
143      */
144     selected: function () {
145         this._isSelected = true;
146     },
147 
148     /**
149      * set the cc.MenuItem unselected same as setIsSelected(false)
150      */
151     unselected: function () {
152         this._isSelected = false;
153     },
154 
155     /**
156      * set the callback to the menu item
157      * @param {function|String} callback
158      * @param {cc.Node} target
159      */
160     setCallback: function (callback, target) {
161         this._target = target;
162         this._callback = callback;
163     },
164 
165     /**
166      * call the selector with target
167      */
168     activate: function () {
169         if (this._enabled) {
170             var locTarget = this._target, locCallback = this._callback;
171             if (!locCallback)
172                 return;
173             if (locTarget && cc.isString(locCallback)) {
174                 locTarget[locCallback](this);
175             } else if (locTarget && cc.isFunction(locCallback)) {
176                 locCallback.call(locTarget, this);
177             } else
178                 locCallback(this);
179         }
180     }
181 });
182 
183 var _p = cc.MenuItem.prototype;
184 
185 // Extended properties
186 /** @expose */
187 _p.enabled;
188 cc.defineGetterSetter(_p, "enabled", _p.isEnabled, _p.setEnabled);
189 
190 /**
191  * creates an empty menu item with target and callback<br/>
192  * Not recommended to use the base class, should use more defined menu item classes
193  * @deprecated since v3.0, please use new cc.MenuItem(callback,target) instead
194  * @param {function|String} callback callback
195  * @param {cc.Node} target
196  * @return {cc.MenuItem}
197  */
198 cc.MenuItem.create = function (callback, target) {
199     return new cc.MenuItem(callback, target);
200 };
201 
202 /**
203  *  Any cc.Node that supports the cc.LabelProtocol protocol can be added.<br/>
204  * Supported nodes:<br/>
205  * - cc.BitmapFontAtlas<br/>
206  * - cc.LabelAtlas<br/>
207  * - cc.LabelTTF<br/>
208  * @class
209  * @extends cc.MenuItem
210  * @param {cc.Node} label
211  * @param {function|String} selector
212  * @param {cc.Node} target
213  * @example
214  * var menuitemLabel = new cc.MenuItemLabel(label,selector,target);
215  *
216  * @property {String}   string          - Content string of label item
217  * @property {cc.Node}  label           - Label of label item
218  * @property {cc.Color} disabledColor   - Color of label when it's disabled
219  */
220 cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{
221     _disabledColor: null,
222     _label: null,
223     _originalScale: 0,
224     _colorBackup: null,
225 
226     /**
227      * Constructor of cc.MenuItemLabel
228      * @param {cc.Node} label
229      * @param {function|String} selector
230      * @param {cc.Node} target
231      */
232     ctor: function (label, selector, target) {
233         cc.MenuItem.prototype.ctor.call(this, selector, target);
234         this._disabledColor = null;
235         this._label = null;
236         this._colorBackup = null;
237 
238         if (label) {
239             this._originalScale = 1.0;
240             this._colorBackup = cc.color.WHITE;
241             this._disabledColor = cc.color(126, 126, 126);
242             this.setLabel(label);
243 
244             this.cascadeColor = true;
245             this.cascadeOpacity = true;
246         }
247     },
248 
249     /**
250      * return the disable color for this cc.MenuItemLabel
251      * @return {cc.Color}
252      */
253     getDisabledColor: function () {
254         return this._disabledColor;
255     },
256 
257     /**
258      * set the disable color for this cc.MenuItemLabel
259      * @param {cc.Color} color
260      */
261     setDisabledColor: function (color) {
262         this._disabledColor = color;
263     },
264 
265     /**
266      * return label of cc.MenuItemLabel
267      * @return {cc.Node}
268      */
269     getLabel: function () {
270         return this._label;
271     },
272 
273     /**
274      * set a label for cc.MenuItemLabel
275      * @param {cc.Node} label
276      */
277     setLabel: function (label) {
278         if (label) {
279             this.addChild(label);
280             label.anchorX = 0;
281             label.anchorY = 0;
282             this.width = label.width;
283             this.height = label.height;
284         }
285 
286         if (this._label) {
287             this.removeChild(this._label, true);
288         }
289 
290         this._label = label;
291     },
292 
293     /**
294      * set enable value to cc.MenuItemLabel
295      * @param {Boolean} enabled
296      */
297     setEnabled: function (enabled) {
298         if (this._enabled !== enabled) {
299             var locLabel = this._label;
300             if (!enabled) {
301                 this._colorBackup = locLabel.color;
302                 locLabel.color = this._disabledColor;
303             } else {
304                 locLabel.color = this._colorBackup;
305             }
306         }
307         cc.MenuItem.prototype.setEnabled.call(this, enabled);
308     },
309 
310     /**
311      * set opacity for cc.MenuItemLabel
312      * @param {Number} opacity from 0-255
313      */
314     setOpacity: function (opacity) {
315         this._label.opacity = opacity;
316     },
317 
318     /**
319      * return the opacity of cc.MenuItemLabel
320      * @return {Number}
321      */
322     getOpacity: function () {
323         return this._label.opacity;
324     },
325 
326     /**
327      * set the opacity for cc.MenuItemLabel
328      * @param {cc.Color} color
329      */
330     setColor: function (color) {
331         this._label.color = color;
332     },
333 
334     /**
335      * return the color of cc.MenuItemLabel
336      * @return {cc.Color}
337      */
338     getColor: function () {
339         return this._label.color;
340     },
341 
342     /**
343      * initializes a cc.MenuItemLabel with a label
344      * @param {cc.Node} label
345      * @param {function|String} selector
346      * @param {cc.Node} target
347      * @return {Boolean}
348      */
349     initWithLabel: function (label, selector, target) {
350         this.initWithCallback(selector, target);
351         this._originalScale = 1.0;
352         this._colorBackup = cc.color.WHITE;
353         this._disabledColor = cc.color(126, 126, 126);
354         this.setLabel(label);
355 
356         this.cascadeColor = true;
357         this.cascadeOpacity = true;
358 
359         return true;
360     },
361 
362     /**
363      * set the string for  cc.MenuItemLabel
364      * @param {String} label
365      */
366     setString: function (label) {
367         this._label.string = label;
368         this.width = this._label.width;
369         this.height = this._label.height;
370     },
371     /**
372      * return the string of cc.MenuItemLabel
373      * @returns {*|string|_p.string|ret.string|q.string|String}
374      */
375     getString: function () {
376         return this._label.string;
377     },
378 
379     /**
380      * activate the menu item
381      */
382     activate: function () {
383         if (this._enabled) {
384             this.stopAllActions();
385             this.scale = this._originalScale;
386             cc.MenuItem.prototype.activate.call(this);
387         }
388     },
389 
390     /**
391      * menu item is selected (runs callback)
392      */
393     selected: function () {
394         if (this._enabled) {
395             cc.MenuItem.prototype.selected.call(this);
396 
397             var action = this.getActionByTag(cc.ZOOM_ACTION_TAG);
398             if (action)
399                 this.stopAction(action);
400             else
401                 this._originalScale = this.scale;
402 
403             var zoomAction = cc.scaleTo(0.1, this._originalScale * 1.2);
404             zoomAction.setTag(cc.ZOOM_ACTION_TAG);
405             this.runAction(zoomAction);
406         }
407     },
408 
409     /**
410      * menu item goes back to unselected state
411      */
412     unselected: function () {
413         if (this._enabled) {
414             cc.MenuItem.prototype.unselected.call(this);
415             this.stopActionByTag(cc.ZOOM_ACTION_TAG);
416             var zoomAction = cc.scaleTo(0.1, this._originalScale);
417             zoomAction.setTag(cc.ZOOM_ACTION_TAG);
418             this.runAction(zoomAction);
419         }
420     }
421 });
422 
423 var _p = cc.MenuItemLabel.prototype;
424 
425 // Extended properties
426 /** @expose */
427 _p.string;
428 cc.defineGetterSetter(_p, "string", _p.getString, _p.setString);
429 /** @expose */
430 _p.disabledColor;
431 cc.defineGetterSetter(_p, "disabledColor", _p.getDisabledColor, _p.setDisabledColor);
432 /** @expose */
433 _p.label;
434 cc.defineGetterSetter(_p, "label", _p.getLabel, _p.setLabel);
435 
436 
437 /**
438  * @deprecated since v3.0 ,please use new cc.MenuItemLabel(label,selector,target) instead
439  * @param {cc.Node} label
440  * @param {function|String|Null} [selector=]
441  * @param {cc.Node|Null} [target=]
442  * @return {cc.MenuItemLabel}
443  */
444 cc.MenuItemLabel.create = function (label, selector, target) {
445     return new cc.MenuItemLabel(label, selector, target);
446 };
447 
448 /**
449  * Helper class that creates a MenuItemLabel class with a LabelAtlas
450  * @class
451  * @extends cc.MenuItemLabel
452  * @param {String} value
453  * @param {String} charMapFile
454  * @param {Number} itemWidth
455  * @param {Number} itemHeight
456  * @param {String} startCharMap a single character
457  * @param {function|String|Null} callback
458  * @param {cc.Node|Null} target
459  * @example
460  * var menuItem = new cc.MenuItemAtlasFont(param1,param2...);
461  */
462 cc.MenuItemAtlasFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemAtlasFont# */{
463 
464     /**
465      * the contructor of cc.MenuItemAtlasFont
466      * @param {String} value
467      * @param {String} charMapFile
468      * @param {Number} itemWidth
469      * @param {Number} itemHeight
470      * @param {String} startCharMap a single character
471      * @param {function|String|Null} callback
472      * @param {cc.Node|Null} target
473      */
474     ctor: function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) {
475         var label;
476         if (value && value.length > 0) {
477             label = new cc.LabelAtlas(value, charMapFile, itemWidth, itemHeight, startCharMap);
478         }
479 
480         cc.MenuItemLabel.prototype.ctor.call(this, label, callback, target);
481     },
482 
483     /**
484      * initializes a cc.MenuItemAtlasFont with string
485      * @param {String} value
486      * @param {String} charMapFile
487      * @param {Number} itemWidth
488      * @param {Number} itemHeight
489      * @param {String} startCharMap a single character
490      * @param {function|String|Null} callback
491      * @param {cc.Node|Null} target
492      * @return {Boolean}
493      */
494     initWithString: function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) {
495         if (!value || value.length === 0)
496             throw "cc.MenuItemAtlasFont.initWithString(): value should be non-null and its length should be greater than 0";
497 
498         var label = new cc.LabelAtlas();
499         label.initWithString(value, charMapFile, itemWidth, itemHeight, startCharMap);
500         if (this.initWithLabel(label, callback, target)) {
501             // do something ?
502         }
503         return true;
504     }
505 });
506 
507 /**
508  * create menu item from string with font
509  * @deprecated since v3.0 ,please use new cc.MenuItemAtlasFont() instead.
510  * @param {String} value the text to display
511  * @param {String} charMapFile the character map file
512  * @param {Number} itemWidth
513  * @param {Number} itemHeight
514  * @param {String} startCharMap a single character
515  * @param {function|String|Null} [callback=null]
516  * @param {cc.Node|Null} [target=]
517  * @return {cc.MenuItemAtlasFont}
518  */
519 cc.MenuItemAtlasFont.create = function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) {
520     return new cc.MenuItemAtlasFont(value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target);
521 };
522 
523 /**
524  * Helper class that creates a CCMenuItemLabel class with a Label
525  * @class
526  * @extends cc.MenuItemLabel
527  * @param {String} value text for the menu item
528  * @param {function|String} callback
529  * @param {cc.Node} target
530  * @example
531  * var menuItem = new cc.MenuItemFont(value, callback, target);
532  *
533  * @property {Number}   fontSize    - Font size of font item
534  * @property {String}   fontName    - Font name of font item
535  */
536 cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{
537     _fontSize: null,
538     _fontName: null,
539 
540     /**
541      * Constructor of cc.MenuItemFont
542      * @param {String} value text for the menu item
543      * @param {function|String} callback
544      * @param {cc.Node} target
545      */
546     ctor: function (value, callback, target) {
547         var label;
548         if (value && value.length > 0) {
549             this._fontName = cc._globalFontName;
550             this._fontSize = cc._globalFontSize;
551             label = new cc.LabelTTF(value, this._fontName, this._fontSize);
552         }
553         else {
554             this._fontSize = 0;
555             this._fontName = "";
556         }
557 
558         cc.MenuItemLabel.prototype.ctor.call(this, label, callback, target);
559     },
560 
561     /**
562      * initializes cc.MenuItemFont with  string
563      * @param {String} value text for the menu item
564      * @param {function|String} callback
565      * @param {cc.Node} target
566      * @return {Boolean}
567      */
568     initWithString: function (value, callback, target) {
569         if (!value || value.length === 0)
570             throw "Value should be non-null and its length should be greater than 0";
571 
572         this._fontName = cc._globalFontName;
573         this._fontSize = cc._globalFontSize;
574 
575         var label = new cc.LabelTTF(value, this._fontName, this._fontSize);
576         if (this.initWithLabel(label, callback, target)) {
577             // do something ?
578         }
579         return true;
580     },
581 
582     /**
583      * set the font size for cc.MenuItemFont
584      * @param {Number} s
585      */
586     setFontSize: function (s) {
587         this._fontSize = s;
588         this._recreateLabel();
589     },
590 
591     /**
592      *return the font size of cc.MenuItemFont
593      * @return {Number}
594      */
595     getFontSize: function () {
596         return this._fontSize;
597     },
598 
599     /**
600      * set the font name for cc.MenuItemFont
601      * @param {String} name
602      */
603     setFontName: function (name) {
604         this._fontName = name;
605         this._recreateLabel();
606     },
607 
608     /**
609      * return the font name for cc.MenuItemFont
610      * @return {String}
611      */
612     getFontName: function () {
613         return this._fontName;
614     },
615 
616     _recreateLabel: function () {
617         var label = new cc.LabelTTF(this._label.string, this._fontName, this._fontSize);
618         this.setLabel(label);
619     }
620 });
621 
622 /**
623  * a shared function to set the fontSize for menuitem font
624  * @param {Number} fontSize
625  */
626 cc.MenuItemFont.setFontSize = function (fontSize) {
627     cc._globalFontSize = fontSize;
628 };
629 
630 /**
631  * a shared function to get the font size for menuitem font
632  * @return {Number}
633  */
634 cc.MenuItemFont.fontSize = function () {
635     return cc._globalFontSize;
636 };
637 
638 /**
639  * a shared function to set the fontsize for menuitem font
640  * @param name
641  */
642 cc.MenuItemFont.setFontName = function (name) {
643     if (cc._globalFontNameRelease) {
644         cc._globalFontName = '';
645     }
646     cc._globalFontName = name;
647     cc._globalFontNameRelease = true;
648 };
649 
650 var _p = cc.MenuItemFont.prototype;
651 
652 // Extended properties
653 /** @expose */
654 _p.fontSize;
655 cc.defineGetterSetter(_p, "fontSize", _p.getFontSize, _p.setFontSize);
656 /** @expose */
657 _p.fontName;
658 cc.defineGetterSetter(_p, "fontName", _p.getFontName, _p.setFontName);
659 
660 
661 /**
662  * a shared function to get the font name for menuitem font
663  * @return {String}
664  */
665 cc.MenuItemFont.fontName = function () {
666     return cc._globalFontName;
667 };
668 
669 /**
670  * create a menu item from string
671  * @deprecated since v3.0, please use new construction instead
672  * @param {String} value the text to display
673  * @param {String|function|Null} callback the callback to run, either in function name or pass in the actual function
674  * @param {cc.Node|Null} target the target to run callback
675  * @return {cc.MenuItemFont}
676  */
677 cc.MenuItemFont.create = function (value, callback, target) {
678     return new cc.MenuItemFont(value, callback, target);
679 };
680 
681 
682 /**
683  * CCMenuItemSprite accepts CCNode<CCRGBAProtocol> objects as items.<br/>
684  * The images has 3 different states:<br/>
685  *   - unselected image<br/>
686  *   - selected image<br/>
687  *   - disabled image<br/>
688  * @class
689  * @extends cc.MenuItem
690  * @param {Image|Null} normalSprite normal state image
691  * @param {Image|Null} selectedSprite selected state image
692  * @param {Image|cc.Node|Null} three disabled state image OR target node
693  * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
694  * @param {String|function|Null} five callback function name in string or actual function
695  *
696  * @example
697  * var item = new cc.MenuItemSprite(normalImage)//create a menu item from a sprite with no functionality
698  * var item = new cc.MenuItemSprite(normalImage, selectedImage)//create a menu Item, nothing will happen when clicked
699  * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage)//same above, but with disabled state image
700  * var item = new cc.MenuItemSprite(normalImage, SelectedImage, 'callback', targetNode)//create a menu item, when clicked runs targetNode.callback()
701  * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage, targetNode.callback, targetNode)
702  * //same as above, but with disabled image, and passing in callback function
703  *
704  * @property {cc.Sprite}    normalImage     - Sprite in normal state
705  * @property {cc.Sprite}    selectedImage     - Sprite in selected state
706  * @property {cc.Sprite}    disabledImage     - Sprite in disabled state
707  */
708 cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{
709     _normalImage: null,
710     _selectedImage: null,
711     _disabledImage: null,
712 
713     /**
714      * Constructor of cc.MenuItemSprite
715      * @param {Image|Null} normalSprite normal state image
716      * @param {Image|Null} selectedSprite selected state image
717      * @param {Image|cc.Node|Null} three disabled state image OR target node
718      * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
719      * @param {String|function|Null} five callback function name in string or actual function
720      */
721     ctor: function (normalSprite, selectedSprite, three, four, five) {
722         cc.MenuItem.prototype.ctor.call(this);
723         this._normalImage = null;
724         this._selectedImage = null;
725         this._disabledImage = null;
726 
727         if (selectedSprite !== undefined) {
728             //normalSprite = normalSprite;
729             //selectedSprite = selectedSprite;
730             var disabledImage, target, callback;
731             //when you send 4 arguments, five is undefined
732             if (five !== undefined) {
733                 disabledImage = three;
734                 callback = four;
735                 target = five;
736             } else if (four !== undefined && cc.isFunction(four)) {
737                 disabledImage = three;
738                 callback = four;
739             } else if (four !== undefined && cc.isFunction(three)) {
740                 target = four;
741                 callback = three;
742                 disabledImage = null;
743             } else if (three === undefined) {
744                 disabledImage = null;
745             }
746             this.initWithNormalSprite(normalSprite, selectedSprite, disabledImage, callback, target);
747         }
748     },
749 
750     /**
751      * return the normal status image(cc.Sprite)
752      * @return {cc.Sprite}
753      */
754     getNormalImage: function () {
755         return this._normalImage;
756     },
757 
758     /**
759      * set the normal status image(cc.Sprite)
760      * @param {cc.Sprite} normalImage
761      */
762     setNormalImage: function (normalImage) {
763         if (this._normalImage === normalImage) {
764             return;
765         }
766         if (normalImage) {
767             this.addChild(normalImage, 0, cc.NORMAL_TAG);
768             normalImage.anchorX = 0;
769             normalImage.anchorY = 0;
770         }
771         if (this._normalImage) {
772             this.removeChild(this._normalImage, true);
773         }
774 
775         this._normalImage = normalImage;
776         this.width = this._normalImage.width;
777         this.height = this._normalImage.height;
778         this._updateImagesVisibility();
779 
780         if (normalImage.textureLoaded && !normalImage.textureLoaded()) {
781             normalImage.addEventListener("load", function (sender) {
782                 this.width = sender.width;
783                 this.height = sender.height;
784             }, this);
785         }
786     },
787 
788     /**
789      * return the selected status image(cc.Sprite) of cc.MenuItemSprite
790      * @return {cc.Sprite}
791      */
792     getSelectedImage: function () {
793         return this._selectedImage;
794     },
795 
796     /**
797      * set the selected status image(cc.Sprite)
798      * @param {cc.Sprite} selectedImage
799      */
800     setSelectedImage: function (selectedImage) {
801         if (this._selectedImage === selectedImage)
802             return;
803 
804         if (selectedImage) {
805             this.addChild(selectedImage, 0, cc.SELECTED_TAG);
806             selectedImage.anchorX = 0;
807             selectedImage.anchorY = 0;
808         }
809 
810         if (this._selectedImage) {
811             this.removeChild(this._selectedImage, true);
812         }
813 
814         this._selectedImage = selectedImage;
815         this._updateImagesVisibility();
816     },
817 
818     /**
819      * return the disabled status of cc.MenuItemSprite
820      * @return {cc.Sprite}
821      */
822     getDisabledImage: function () {
823         return this._disabledImage;
824     },
825 
826     /**
827      * set the disabled status image(cc.Sprite)
828      * @param {cc.Sprite} disabledImage
829      */
830     setDisabledImage: function (disabledImage) {
831         if (this._disabledImage === disabledImage)
832             return;
833 
834         if (disabledImage) {
835             this.addChild(disabledImage, 0, cc.DISABLE_TAG);
836             disabledImage.anchorX = 0;
837             disabledImage.anchorY = 0;
838         }
839 
840         if (this._disabledImage)
841             this.removeChild(this._disabledImage, true);
842 
843         this._disabledImage = disabledImage;
844         this._updateImagesVisibility();
845     },
846 
847     /**
848      * initializes cc.MenuItemSprite with a cc.Sprite
849      * @param {cc.Node} normalSprite
850      * @param {cc.Node} selectedSprite
851      * @param {cc.Node} disabledSprite
852      * @param {function|String} callback
853      * @param {cc.Node} target
854      * @return {Boolean}
855      */
856     initWithNormalSprite: function (normalSprite, selectedSprite, disabledSprite, callback, target) {
857         this.initWithCallback(callback, target);
858         this.setNormalImage(normalSprite);
859         this.setSelectedImage(selectedSprite);
860         this.setDisabledImage(disabledSprite);
861         var locNormalImage = this._normalImage;
862         if (locNormalImage) {
863             this.width = locNormalImage.width;
864             this.height = locNormalImage.height;
865 
866             if (locNormalImage.textureLoaded && !locNormalImage.textureLoaded()) {
867                 locNormalImage.addEventListener("load", function (sender) {
868                     this.width = sender.width;
869                     this.height = sender.height;
870                     this.cascadeColor = true;
871                     this.cascadeOpacity = true;
872                 }, this);
873             }
874         }
875         this.cascadeColor = true;
876         this.cascadeOpacity = true;
877         return true;
878     },
879 
880     /**
881      * set the color for cc.MenuItemSprite
882      * @param {cc.Color} color
883      */
884     setColor: function (color) {
885         this._normalImage.color = color;
886 
887         if (this._selectedImage)
888             this._selectedImage.color = color;
889 
890         if (this._disabledImage)
891             this._disabledImage.color = color;
892     },
893 
894     /**
895      * return the color of cc.MenuItemSprite
896      * @return {cc.Color}
897      */
898     getColor: function () {
899         return this._normalImage.color;
900     },
901 
902     /**
903      * set the opacity for cc.MenuItemSprite
904      * @param {Number} opacity 0 - 255
905      */
906     setOpacity: function (opacity) {
907         this._normalImage.opacity = opacity;
908 
909         if (this._selectedImage)
910             this._selectedImage.opacity = opacity;
911 
912         if (this._disabledImage)
913             this._disabledImage.opacity = opacity;
914     },
915 
916     /**
917      * return the opacity of cc.MenuItemSprite
918      * @return {Number} opacity from 0 - 255
919      */
920     getOpacity: function () {
921         return this._normalImage.opacity;
922     },
923 
924     /**
925      * menu item is selected (runs callback)
926      */
927     selected: function () {
928         cc.MenuItem.prototype.selected.call(this);
929         if (this._normalImage) {
930             if (this._disabledImage)
931                 this._disabledImage.visible = false;
932 
933             if (this._selectedImage) {
934                 this._normalImage.visible = false;
935                 this._selectedImage.visible = true;
936             } else
937                 this._normalImage.visible = true;
938         }
939     },
940 
941     /**
942      * menu item goes back to unselected state
943      */
944     unselected: function () {
945         cc.MenuItem.prototype.unselected.call(this);
946         if (this._normalImage) {
947             this._normalImage.visible = true;
948 
949             if (this._selectedImage)
950                 this._selectedImage.visible = false;
951 
952             if (this._disabledImage)
953                 this._disabledImage.visible = false;
954         }
955     },
956 
957     /**
958      * set cc.MenuItemSprite  enable to receive the touch event
959      * @param {Boolean} bEnabled
960      */
961     setEnabled: function (bEnabled) {
962         if (this._enabled !== bEnabled) {
963             cc.MenuItem.prototype.setEnabled.call(this, bEnabled);
964             this._updateImagesVisibility();
965         }
966     },
967 
968     _updateImagesVisibility: function () {
969         var locNormalImage = this._normalImage, locSelImage = this._selectedImage, locDisImage = this._disabledImage;
970         if (this._enabled) {
971             if (locNormalImage)
972                 locNormalImage.visible = true;
973             if (locSelImage)
974                 locSelImage.visible = false;
975             if (locDisImage)
976                 locDisImage.visible = false;
977         } else {
978             if (locDisImage) {
979                 if (locNormalImage)
980                     locNormalImage.visible = false;
981                 if (locSelImage)
982                     locSelImage.visible = false;
983                 if (locDisImage)
984                     locDisImage.visible = true;
985             } else {
986                 if (locNormalImage)
987                     locNormalImage.visible = true;
988                 if (locSelImage)
989                     locSelImage.visible = false;
990             }
991         }
992     }
993 });
994 
995 var _p = cc.MenuItemSprite.prototype;
996 
997 // Extended properties
998 /** @expose */
999 _p.normalImage;
1000 cc.defineGetterSetter(_p, "normalImage", _p.getNormalImage, _p.setNormalImage);
1001 /** @expose */
1002 _p.selectedImage;
1003 cc.defineGetterSetter(_p, "selectedImage", _p.getSelectedImage, _p.setSelectedImage);
1004 /** @expose */
1005 _p.disabledImage;
1006 cc.defineGetterSetter(_p, "disabledImage", _p.getDisabledImage, _p.setDisabledImage);
1007 
1008 /**
1009  * create a menu item from sprite
1010  * @deprecated since v3.0 please use new cc.MenuItemSprite(normalSprite, selectedSprite, three, four, five) instead
1011  * @param {Image} normalSprite normal state image
1012  * @param {Image|Null} selectedSprite selected state image
1013  * @param {Image|cc.Node|Null} three disabled state image OR target node
1014  * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
1015  * @param {String|function|Null} five callback function name in string or actual function
1016  * @return {cc.MenuItemSprite}
1017  */
1018 cc.MenuItemSprite.create = function (normalSprite, selectedSprite, three, four, five) {
1019     return new cc.MenuItemSprite(normalSprite, selectedSprite, three, four, five || undefined);
1020 };
1021 
1022 /**
1023  * cc.MenuItemImage accepts images as items.<br/>
1024  * The images has 3 different states:<br/>
1025  * - unselected image<br/>
1026  * - selected image<br/>
1027  * - disabled image<br/>
1028  * <br/>
1029  * For best results try that all images are of the same size<br/>
1030  * @class
1031  * @extends cc.MenuItemSprite
1032  * @param {string|null} normalImage
1033  * @param {string|null} selectedImage
1034  * @param {string|null} disabledImage
1035  * @param {function|string|null} callback
1036  * @param {cc.Node|null} target
1037  * @example
1038  * var menuItem = new cc.MenuItemImage(normalImage, selectedImage, three, four, five);
1039  */
1040 cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{
1041 
1042     /**
1043      * Constructor of cc.MenuItemImage
1044      * @param {string|null} normalImage
1045      * @param {string|null} selectedImage
1046      * @param {string|null} disabledImage
1047      * @param {function|string|null} callback
1048      * @param {cc.Node|null} target
1049      */
1050     ctor: function (normalImage, selectedImage, three, four, five) {
1051         var normalSprite = null,
1052             selectedSprite = null,
1053             disabledSprite = null,
1054             callback = null,
1055             target = null;
1056 
1057         if (normalImage === undefined) {
1058             cc.MenuItemSprite.prototype.ctor.call(this);
1059         }
1060         else {
1061             normalSprite = new cc.Sprite(normalImage);
1062             selectedImage &&
1063             (selectedSprite = new cc.Sprite(selectedImage));
1064             if (four === undefined) {
1065                 callback = three;
1066             }
1067             else if (five === undefined) {
1068                 callback = three;
1069                 target = four;
1070             }
1071             else if (five) {
1072                 disabledSprite = new cc.Sprite(three);
1073                 callback = four;
1074                 target = five;
1075             }
1076             cc.MenuItemSprite.prototype.ctor.call(this, normalSprite, selectedSprite, disabledSprite, callback, target);
1077         }
1078     },
1079 
1080     /**
1081      * sets the sprite frame for the normal image
1082      * @param {cc.SpriteFrame} frame
1083      */
1084     setNormalSpriteFrame: function (frame) {
1085         this.setNormalImage(new cc.Sprite(frame));
1086     },
1087 
1088     /**
1089      * sets the sprite frame for the selected image
1090      * @param {cc.SpriteFrame} frame
1091      */
1092     setSelectedSpriteFrame: function (frame) {
1093         this.setSelectedImage(new cc.Sprite(frame));
1094     },
1095 
1096     /**
1097      * sets the sprite frame for the disabled image
1098      * @param {cc.SpriteFrame} frame
1099      */
1100     setDisabledSpriteFrame: function (frame) {
1101         this.setDisabledImage(new cc.Sprite(frame));
1102     },
1103 
1104     /**
1105      * initializes a cc.MenuItemImage
1106      * @param {string|null} normalImage
1107      * @param {string|null} selectedImage
1108      * @param {string|null} disabledImage
1109      * @param {function|string|null} callback
1110      * @param {cc.Node|null} target
1111      * @returns {boolean}
1112      */
1113     initWithNormalImage: function (normalImage, selectedImage, disabledImage, callback, target) {
1114         var normalSprite = null;
1115         var selectedSprite = null;
1116         var disabledSprite = null;
1117 
1118         if (normalImage) {
1119             normalSprite = new cc.Sprite(normalImage);
1120         }
1121         if (selectedImage) {
1122             selectedSprite = new cc.Sprite(selectedImage);
1123         }
1124         if (disabledImage) {
1125             disabledSprite = new cc.Sprite(disabledImage);
1126         }
1127         return this.initWithNormalSprite(normalSprite, selectedSprite, disabledSprite, callback, target);
1128     }
1129 });
1130 
1131 /**
1132  * creates a new menu item image
1133  * @deprecated since v3.0, please use new cc.MenuItemImage(normalImage, selectedImage, three, four, five) instead.
1134  * @param {String} normalImage file name for normal state
1135  * @param {String} selectedImage image for selected state
1136  * @param {String|cc.Node} three Disabled image OR callback function
1137  * @param {String|function|Null} [four] callback function, either name in string or pass the whole function OR the target
1138  * @param {cc.Node|String|function|Null} [five] cc.Node target to run callback when clicked
1139  * @return {cc.MenuItemImage}
1140  */
1141 cc.MenuItemImage.create = function (normalImage, selectedImage, three, four, five) {
1142     return new cc.MenuItemImage(normalImage, selectedImage, three, four, five);
1143 };
1144 
1145 
1146 /**
1147  * A simple container class that "toggles" it's inner items<br/>
1148  * The inner items can be any MenuItem
1149  * @class
1150  * @extends cc.MenuItem
1151  *
1152  * @property {Array}    subItems        - Sub items
1153  * @property {Number}   selectedIndex   - Index of selected sub item
1154  *
1155  *@example
1156  * // Example
1157  * //create a toggle item with 2 menu items (which you can then toggle between them later)
1158  * var toggler = new cc.MenuItemToggle( new cc.MenuItemFont("On"), new cc.MenuItemFont("Off"), this.callback, this)
1159  * //Note: the first param is the target, the second is the callback function, afterwards, you can pass in any number of menuitems
1160  *
1161  * //if you pass only 1 variable, then it must be a cc.MenuItem
1162  * var notYetToggler = new cc.MenuItemToggle(cc.MenuItemFont("On"));//it is useless right now, until you add more stuff to it
1163  * notYetToggler.addSubItem(new cc.MenuItemFont("Off"));
1164  * //this is useful for constructing a toggler without a callback function (you wish to control the behavior from somewhere else)
1165  */
1166 cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{
1167     subItems: null,
1168 
1169     _selectedIndex: 0,
1170     _opacity: null,
1171     _color: null,
1172 
1173     /**
1174      * Constructor of cc.MenuItemToggle
1175     */
1176     ctor: function (/*Multiple arguments follow*/) {
1177 
1178         cc.MenuItem.prototype.ctor.call(this);
1179         this._selectedIndex = 0;
1180         this.subItems = [];
1181         this._opacity = 0;
1182         this._color = cc.color.WHITE;
1183 
1184         if(arguments.length > 0)
1185             this.initWithItems(Array.prototype.slice.apply(arguments));
1186 
1187     },
1188 
1189     /**
1190      * return the opacity of cc.MenuItemToggle
1191      * @return {Number}
1192      */
1193     getOpacity: function () {
1194         return this._opacity;
1195     },
1196 
1197     /**
1198      * set the opacity for cc.MenuItemToggle
1199      * @param {Number} opacity
1200      */
1201     setOpacity: function (opacity) {
1202         this._opacity = opacity;
1203         if (this.subItems && this.subItems.length > 0) {
1204             for (var it = 0; it < this.subItems.length; it++) {
1205                 this.subItems[it].opacity = opacity;
1206             }
1207         }
1208         this._color.a = opacity;
1209     },
1210 
1211     /**
1212      * return the color of cc.MenuItemToggle
1213      * @return {cc.Color}
1214      */
1215     getColor: function () {
1216         var locColor = this._color;
1217         return cc.color(locColor.r, locColor.g, locColor.b, locColor.a);
1218     },
1219 
1220     /**
1221      * set the color for cc.MenuItemToggle
1222      * @param {cc.Color} Color
1223      */
1224     setColor: function (color) {
1225         var locColor = this._color;
1226         locColor.r = color.r;
1227         locColor.g = color.g;
1228         locColor.b = color.b;
1229 
1230         if (this.subItems && this.subItems.length > 0) {
1231             for (var it = 0; it < this.subItems.length; it++) {
1232                 this.subItems[it].setColor(color);
1233             }
1234         }
1235 
1236         if (color.a !== undefined && !color.a_undefined) {
1237             this.setOpacity(color.a);
1238         }
1239     },
1240 
1241     /**
1242      * return the index of selected
1243      * @return {Number}
1244      */
1245     getSelectedIndex: function () {
1246         return this._selectedIndex;
1247     },
1248 
1249     /**
1250      * set the seleceted index for cc.MenuItemToggle
1251      * @param {Number} SelectedIndex
1252      */
1253     setSelectedIndex: function (SelectedIndex) {
1254         if (SelectedIndex !== this._selectedIndex) {
1255             this._selectedIndex = SelectedIndex;
1256             var currItem = this.getChildByTag(cc.CURRENT_ITEM);
1257             if (currItem)
1258                 currItem.removeFromParent(false);
1259 
1260             var item = this.subItems[this._selectedIndex];
1261             this.addChild(item, 0, cc.CURRENT_ITEM);
1262             var w = item.width, h = item.height;
1263             this.width = w;
1264             this.height = h;
1265             item.setPosition(w / 2, h / 2);
1266         }
1267     },
1268 
1269     /**
1270      * similar to get children,return the sumItem array.
1271      * @return {Array}
1272      */
1273     getSubItems: function () {
1274         return this.subItems;
1275     },
1276 
1277     /**
1278      * set the subitem for cc.MenuItemToggle
1279      * @param {cc.MenuItem} subItems
1280      */
1281     setSubItems: function (subItems) {
1282         this.subItems = subItems;
1283     },
1284 
1285     /**
1286      * initializes a cc.MenuItemToggle with items
1287      * @param {cc.MenuItem} args[0...last-2] the rest in the array are cc.MenuItems
1288      * @param {function|String} args[last-1] the second item in the args array is the callback
1289      * @param {cc.Node} args[last] the first item in the args array is a target
1290      * @return {Boolean}
1291      */
1292     initWithItems: function (args) {
1293         var l = args.length;
1294         // passing callback.
1295         if (cc.isFunction(args[args.length - 2])) {
1296             this.initWithCallback(args[args.length - 2], args[args.length - 1]);
1297             l = l - 2;
1298         } else if (cc.isFunction(args[args.length - 1])) {
1299             this.initWithCallback(args[args.length - 1], null);
1300             l = l - 1;
1301         } else {
1302             this.initWithCallback(null, null);
1303         }
1304 
1305         var locSubItems = this.subItems;
1306         locSubItems.length = 0;
1307         for (var i = 0; i < l; i++) {
1308             if (args[i])
1309                 locSubItems.push(args[i]);
1310         }
1311         this._selectedIndex = cc.UINT_MAX;
1312         this.setSelectedIndex(0);
1313 
1314         this.cascadeColor = true;
1315         this.cascadeOpacity = true;
1316 
1317         return true;
1318     },
1319 
1320     /**
1321      * add the subitem for cc.MenuItemToggle
1322      * @param {cc.MenuItem} item
1323      */
1324     addSubItem: function (item) {
1325         this.subItems.push(item);
1326     },
1327 
1328     /**
1329      * activate the menu item
1330      */
1331     activate: function () {
1332         // update index
1333         if (this._enabled) {
1334             var newIndex = (this._selectedIndex + 1) % this.subItems.length;
1335             this.setSelectedIndex(newIndex);
1336         }
1337         cc.MenuItem.prototype.activate.call(this);
1338     },
1339 
1340     /**
1341      * menu item is selected (runs callback)
1342      */
1343     selected: function () {
1344         cc.MenuItem.prototype.selected.call(this);
1345         this.subItems[this._selectedIndex].selected();
1346     },
1347 
1348     /**
1349      * menu item goes back to unselected state
1350      */
1351     unselected: function () {
1352         cc.MenuItem.prototype.unselected.call(this);
1353         this.subItems[this._selectedIndex].unselected();
1354     },
1355 
1356     /**
1357      * set the enable status for cc.MenuItemToggle
1358      * @param {Boolean} enabled
1359      */
1360     setEnabled: function (enabled) {
1361         if (this._enabled !== enabled) {
1362             cc.MenuItem.prototype.setEnabled.call(this, enabled);
1363             var locItems = this.subItems;
1364             if (locItems && locItems.length > 0) {
1365                 for (var it = 0; it < locItems.length; it++)
1366                     locItems[it].enabled = enabled;
1367             }
1368         }
1369     },
1370 
1371     /**
1372      * returns the selected item   (deprecated in -x, please use getSelectedItem instead.)
1373      * @return {cc.MenuItem}
1374      */
1375     selectedItem: function () {
1376         return this.subItems[this._selectedIndex];
1377     },
1378 
1379     /**
1380      * returns the selected item.
1381      * @return {cc.MenuItem}
1382      */
1383     getSelectedItem: function() {
1384         return this.subItems[this._selectedIndex];
1385     },
1386 
1387     /**
1388      * * <p>
1389      *     Event callback that is invoked every time when cc.MenuItemToggle enters the 'stage'.                                   <br/>
1390      *     If the cc.MenuItemToggle enters the 'stage' with a transition, this event is called when the transition starts.        <br/>
1391      *     During onEnter you can't access a "sister/brother" node.                                                    <br/>
1392      *     If you override onEnter, you must call its parent's onEnter function with this._super().
1393      * </p>
1394      */
1395     onEnter: function () {
1396         cc.Node.prototype.onEnter.call(this);
1397         this.setSelectedIndex(this._selectedIndex);
1398     }
1399 });
1400 
1401 var _p = cc.MenuItemToggle.prototype;
1402 
1403 // Extended properties
1404 /** @expose */
1405 _p.selectedIndex;
1406 cc.defineGetterSetter(_p, "selectedIndex", _p.getSelectedIndex, _p.setSelectedIndex);
1407 
1408 
1409 /**
1410  * create a simple container class that "toggles" it's inner items<br/>
1411  * The inner items can be any MenuItem
1412  * @deprecated since v3.0 please use new cc.MenuItemToggle(params) instead
1413  * @return {cc.MenuItemToggle}
1414  * @example
1415  */
1416 cc.MenuItemToggle.create = function (/*Multiple arguments follow*/) {
1417     if ((arguments.length > 0) && (arguments[arguments.length - 1] == null))
1418         cc.log("parameters should not be ending with null in Javascript");
1419     var ret = new cc.MenuItemToggle();
1420     ret.initWithItems(Array.prototype.slice.apply(arguments));
1421     return ret;
1422 };
1423