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.setCascadeColorEnabled(true);
245             this.setCascadeOpacityEnabled(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             label.setCascadeColorEnabled(true);
285         }
286 
287         if (this._label) {
288             this.removeChild(this._label, true);
289         }
290 
291         this._label = label;
292     },
293 
294     /**
295      * set enable value to cc.MenuItemLabel
296      * @param {Boolean} enabled
297      */
298     setEnabled: function (enabled) {
299         if (this._enabled !== enabled) {
300             if (!enabled) {
301                 this._colorBackup = this.color;
302                 this.setColor(this._disabledColor);
303             } else {
304                 this.setColor(this._colorBackup);
305             }
306         }
307         cc.MenuItem.prototype.setEnabled.call(this, enabled);
308     },
309 
310     /**
311      * initializes a cc.MenuItemLabel with a label
312      * @param {cc.Node} label
313      * @param {function|String} selector
314      * @param {cc.Node} target
315      * @return {Boolean}
316      */
317     initWithLabel: function (label, selector, target) {
318         this.initWithCallback(selector, target);
319         this._originalScale = 1.0;
320         this._colorBackup = cc.color.WHITE;
321         this._disabledColor = cc.color(126, 126, 126);
322         this.setLabel(label);
323 
324         this.setCascadeColorEnabled(true);
325         this.setCascadeOpacityEnabled(true);
326 
327         return true;
328     },
329 
330     /**
331      * set the string for  cc.MenuItemLabel
332      * @param {String} label
333      */
334     setString: function (label) {
335         this._label.string = label;
336         this.width = this._label.width;
337         this.height = this._label.height;
338     },
339     /**
340      * return the string of cc.MenuItemLabel
341      * @returns {*|string|_p.string|ret.string|q.string|String}
342      */
343     getString: function () {
344         return this._label.string;
345     },
346 
347     /**
348      * activate the menu item
349      */
350     activate: function () {
351         if (this._enabled) {
352             this.stopAllActions();
353             this.scale = this._originalScale;
354             cc.MenuItem.prototype.activate.call(this);
355         }
356     },
357 
358     /**
359      * menu item is selected (runs callback)
360      */
361     selected: function () {
362         if (this._enabled) {
363             cc.MenuItem.prototype.selected.call(this);
364 
365             var action = this.getActionByTag(cc.ZOOM_ACTION_TAG);
366             if (action)
367                 this.stopAction(action);
368             else
369                 this._originalScale = this.scale;
370 
371             var zoomAction = cc.scaleTo(0.1, this._originalScale * 1.2);
372             zoomAction.setTag(cc.ZOOM_ACTION_TAG);
373             this.runAction(zoomAction);
374         }
375     },
376 
377     /**
378      * menu item goes back to unselected state
379      */
380     unselected: function () {
381         if (this._enabled) {
382             cc.MenuItem.prototype.unselected.call(this);
383             this.stopActionByTag(cc.ZOOM_ACTION_TAG);
384             var zoomAction = cc.scaleTo(0.1, this._originalScale);
385             zoomAction.setTag(cc.ZOOM_ACTION_TAG);
386             this.runAction(zoomAction);
387         }
388     }
389 });
390 
391 var _p = cc.MenuItemLabel.prototype;
392 
393 // Extended properties
394 /** @expose */
395 _p.string;
396 cc.defineGetterSetter(_p, "string", _p.getString, _p.setString);
397 /** @expose */
398 _p.disabledColor;
399 cc.defineGetterSetter(_p, "disabledColor", _p.getDisabledColor, _p.setDisabledColor);
400 /** @expose */
401 _p.label;
402 cc.defineGetterSetter(_p, "label", _p.getLabel, _p.setLabel);
403 
404 
405 /**
406  * @deprecated since v3.0 ,please use new cc.MenuItemLabel(label,selector,target) instead
407  * @param {cc.Node} label
408  * @param {function|String|Null} [selector=]
409  * @param {cc.Node|Null} [target=]
410  * @return {cc.MenuItemLabel}
411  */
412 cc.MenuItemLabel.create = function (label, selector, target) {
413     return new cc.MenuItemLabel(label, selector, target);
414 };
415 
416 /**
417  * Helper class that creates a MenuItemLabel class with a LabelAtlas
418  * @class
419  * @extends cc.MenuItemLabel
420  * @param {String} value
421  * @param {String} charMapFile
422  * @param {Number} itemWidth
423  * @param {Number} itemHeight
424  * @param {String} startCharMap a single character
425  * @param {function|String|Null} callback
426  * @param {cc.Node|Null} target
427  * @example
428  * var menuItem = new cc.MenuItemAtlasFont(param1,param2...);
429  */
430 cc.MenuItemAtlasFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemAtlasFont# */{
431 
432     /**
433      * the contructor of cc.MenuItemAtlasFont
434      * @param {String} value
435      * @param {String} charMapFile
436      * @param {Number} itemWidth
437      * @param {Number} itemHeight
438      * @param {String} startCharMap a single character
439      * @param {function|String|Null} callback
440      * @param {cc.Node|Null} target
441      */
442     ctor: function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) {
443         var label;
444         if (value && value.length > 0) {
445             label = new cc.LabelAtlas(value, charMapFile, itemWidth, itemHeight, startCharMap);
446         }
447 
448         cc.MenuItemLabel.prototype.ctor.call(this, label, callback, target);
449     },
450 
451     /**
452      * initializes a cc.MenuItemAtlasFont with string
453      * @param {String} value
454      * @param {String} charMapFile
455      * @param {Number} itemWidth
456      * @param {Number} itemHeight
457      * @param {String} startCharMap a single character
458      * @param {function|String|Null} callback
459      * @param {cc.Node|Null} target
460      * @return {Boolean}
461      */
462     initWithString: function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) {
463         if (!value || value.length === 0)
464             throw "cc.MenuItemAtlasFont.initWithString(): value should be non-null and its length should be greater than 0";
465 
466         var label = new cc.LabelAtlas();
467         label.initWithString(value, charMapFile, itemWidth, itemHeight, startCharMap);
468         if (this.initWithLabel(label, callback, target)) {
469             // do something ?
470         }
471         return true;
472     }
473 });
474 
475 /**
476  * create menu item from string with font
477  * @deprecated since v3.0 ,please use new cc.MenuItemAtlasFont() instead.
478  * @param {String} value the text to display
479  * @param {String} charMapFile the character map file
480  * @param {Number} itemWidth
481  * @param {Number} itemHeight
482  * @param {String} startCharMap a single character
483  * @param {function|String|Null} [callback=null]
484  * @param {cc.Node|Null} [target=]
485  * @return {cc.MenuItemAtlasFont}
486  */
487 cc.MenuItemAtlasFont.create = function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) {
488     return new cc.MenuItemAtlasFont(value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target);
489 };
490 
491 /**
492  * Helper class that creates a CCMenuItemLabel class with a Label
493  * @class
494  * @extends cc.MenuItemLabel
495  * @param {String} value text for the menu item
496  * @param {function|String} callback
497  * @param {cc.Node} target
498  * @example
499  * var menuItem = new cc.MenuItemFont(value, callback, target);
500  *
501  * @property {Number}   fontSize    - Font size of font item
502  * @property {String}   fontName    - Font name of font item
503  */
504 cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{
505     _fontSize: null,
506     _fontName: null,
507 
508     /**
509      * Constructor of cc.MenuItemFont
510      * @param {String} value text for the menu item
511      * @param {function|String} callback
512      * @param {cc.Node} target
513      */
514     ctor: function (value, callback, target) {
515         var label;
516         if (value && value.length > 0) {
517             this._fontName = cc._globalFontName;
518             this._fontSize = cc._globalFontSize;
519             label = new cc.LabelTTF(value, this._fontName, this._fontSize);
520         }
521         else {
522             this._fontSize = 0;
523             this._fontName = "";
524         }
525 
526         cc.MenuItemLabel.prototype.ctor.call(this, label, callback, target);
527     },
528 
529     /**
530      * initializes cc.MenuItemFont with  string
531      * @param {String} value text for the menu item
532      * @param {function|String} callback
533      * @param {cc.Node} target
534      * @return {Boolean}
535      */
536     initWithString: function (value, callback, target) {
537         if (!value || value.length === 0)
538             throw "Value should be non-null and its length should be greater than 0";
539 
540         this._fontName = cc._globalFontName;
541         this._fontSize = cc._globalFontSize;
542 
543         var label = new cc.LabelTTF(value, this._fontName, this._fontSize);
544         if (this.initWithLabel(label, callback, target)) {
545             // do something ?
546         }
547         return true;
548     },
549 
550     /**
551      * set the font size for cc.MenuItemFont
552      * @param {Number} s
553      */
554     setFontSize: function (s) {
555         this._fontSize = s;
556         this._recreateLabel();
557     },
558 
559     /**
560      *return the font size of cc.MenuItemFont
561      * @return {Number}
562      */
563     getFontSize: function () {
564         return this._fontSize;
565     },
566 
567     /**
568      * set the font name for cc.MenuItemFont
569      * @param {String} name
570      */
571     setFontName: function (name) {
572         this._fontName = name;
573         this._recreateLabel();
574     },
575 
576     /**
577      * return the font name for cc.MenuItemFont
578      * @return {String}
579      */
580     getFontName: function () {
581         return this._fontName;
582     },
583 
584     _recreateLabel: function () {
585         var label = new cc.LabelTTF(this._label.string, this._fontName, this._fontSize);
586         this.setLabel(label);
587     }
588 });
589 
590 /**
591  * a shared function to set the fontSize for menuitem font
592  * @param {Number} fontSize
593  */
594 cc.MenuItemFont.setFontSize = function (fontSize) {
595     cc._globalFontSize = fontSize;
596 };
597 
598 /**
599  * a shared function to get the font size for menuitem font
600  * @return {Number}
601  */
602 cc.MenuItemFont.fontSize = function () {
603     return cc._globalFontSize;
604 };
605 
606 /**
607  * a shared function to set the fontsize for menuitem font
608  * @param name
609  */
610 cc.MenuItemFont.setFontName = function (name) {
611     if (cc._globalFontNameRelease) {
612         cc._globalFontName = '';
613     }
614     cc._globalFontName = name;
615     cc._globalFontNameRelease = true;
616 };
617 
618 var _p = cc.MenuItemFont.prototype;
619 
620 // Extended properties
621 /** @expose */
622 _p.fontSize;
623 cc.defineGetterSetter(_p, "fontSize", _p.getFontSize, _p.setFontSize);
624 /** @expose */
625 _p.fontName;
626 cc.defineGetterSetter(_p, "fontName", _p.getFontName, _p.setFontName);
627 
628 
629 /**
630  * a shared function to get the font name for menuitem font
631  * @return {String}
632  */
633 cc.MenuItemFont.fontName = function () {
634     return cc._globalFontName;
635 };
636 
637 /**
638  * create a menu item from string
639  * @deprecated since v3.0, please use new construction instead
640  * @param {String} value the text to display
641  * @param {String|function|Null} callback the callback to run, either in function name or pass in the actual function
642  * @param {cc.Node|Null} target the target to run callback
643  * @return {cc.MenuItemFont}
644  */
645 cc.MenuItemFont.create = function (value, callback, target) {
646     return new cc.MenuItemFont(value, callback, target);
647 };
648 
649 
650 /**
651  * CCMenuItemSprite accepts CCNode<CCRGBAProtocol> objects as items.<br/>
652  * The images has 3 different states:<br/>
653  *   - unselected image<br/>
654  *   - selected image<br/>
655  *   - disabled image<br/>
656  * @class
657  * @extends cc.MenuItem
658  * @param {Image|Null} normalSprite normal state image
659  * @param {Image|Null} selectedSprite selected state image
660  * @param {Image|cc.Node|Null} three disabled state image OR target node
661  * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
662  * @param {String|function|Null} five callback function name in string or actual function
663  *
664  * @example
665  * var item = new cc.MenuItemSprite(normalImage)//create a menu item from a sprite with no functionality
666  * var item = new cc.MenuItemSprite(normalImage, selectedImage)//create a menu Item, nothing will happen when clicked
667  * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage)//same above, but with disabled state image
668  * var item = new cc.MenuItemSprite(normalImage, SelectedImage, 'callback', targetNode)//create a menu item, when clicked runs targetNode.callback()
669  * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage, targetNode.callback, targetNode)
670  * //same as above, but with disabled image, and passing in callback function
671  *
672  * @property {cc.Sprite}    normalImage     - Sprite in normal state
673  * @property {cc.Sprite}    selectedImage     - Sprite in selected state
674  * @property {cc.Sprite}    disabledImage     - Sprite in disabled state
675  */
676 cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{
677     _normalImage: null,
678     _selectedImage: null,
679     _disabledImage: null,
680 
681     /**
682      * Constructor of cc.MenuItemSprite
683      * @param {Image|Null} normalSprite normal state image
684      * @param {Image|Null} selectedSprite selected state image
685      * @param {Image|cc.Node|Null} three disabled state image OR target node
686      * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
687      * @param {String|function|Null} five callback function name in string or actual function
688      */
689     ctor: function (normalSprite, selectedSprite, three, four, five) {
690         cc.MenuItem.prototype.ctor.call(this);
691         this._normalImage = null;
692         this._selectedImage = null;
693         this._disabledImage = null;
694 
695         if (selectedSprite !== undefined) {
696             //normalSprite = normalSprite;
697             //selectedSprite = selectedSprite;
698             var disabledImage, target, callback;
699             //when you send 4 arguments, five is undefined
700             if (five !== undefined) {
701                 disabledImage = three;
702                 callback = four;
703                 target = five;
704             } else if (four !== undefined && cc.isFunction(four)) {
705                 disabledImage = three;
706                 callback = four;
707             } else if (four !== undefined && cc.isFunction(three)) {
708                 target = four;
709                 callback = three;
710                 disabledImage = null;
711             } else if (three === undefined) {
712                 disabledImage = null;
713             }
714             this.initWithNormalSprite(normalSprite, selectedSprite, disabledImage, callback, target);
715         }
716     },
717 
718     /**
719      * return the normal status image(cc.Sprite)
720      * @return {cc.Sprite}
721      */
722     getNormalImage: function () {
723         return this._normalImage;
724     },
725 
726     /**
727      * set the normal status image(cc.Sprite)
728      * @param {cc.Sprite} normalImage
729      */
730     setNormalImage: function (normalImage) {
731         if (this._normalImage === normalImage) {
732             return;
733         }
734         if (normalImage) {
735             this.addChild(normalImage, 0, cc.NORMAL_TAG);
736             normalImage.anchorX = 0;
737             normalImage.anchorY = 0;
738         }
739         if (this._normalImage) {
740             this.removeChild(this._normalImage, true);
741         }
742 
743         this._normalImage = normalImage;
744         this.width = this._normalImage.width;
745         this.height = this._normalImage.height;
746         this._updateImagesVisibility();
747 
748         if (normalImage.textureLoaded && !normalImage.textureLoaded()) {
749             normalImage.addEventListener("load", function (sender) {
750                 this.width = sender.width;
751                 this.height = sender.height;
752             }, this);
753         }
754     },
755 
756     /**
757      * return the selected status image(cc.Sprite) of cc.MenuItemSprite
758      * @return {cc.Sprite}
759      */
760     getSelectedImage: function () {
761         return this._selectedImage;
762     },
763 
764     /**
765      * set the selected status image(cc.Sprite)
766      * @param {cc.Sprite} selectedImage
767      */
768     setSelectedImage: function (selectedImage) {
769         if (this._selectedImage === selectedImage)
770             return;
771 
772         if (selectedImage) {
773             this.addChild(selectedImage, 0, cc.SELECTED_TAG);
774             selectedImage.anchorX = 0;
775             selectedImage.anchorY = 0;
776         }
777 
778         if (this._selectedImage) {
779             this.removeChild(this._selectedImage, true);
780         }
781 
782         this._selectedImage = selectedImage;
783         this._updateImagesVisibility();
784     },
785 
786     /**
787      * return the disabled status of cc.MenuItemSprite
788      * @return {cc.Sprite}
789      */
790     getDisabledImage: function () {
791         return this._disabledImage;
792     },
793 
794     /**
795      * set the disabled status image(cc.Sprite)
796      * @param {cc.Sprite} disabledImage
797      */
798     setDisabledImage: function (disabledImage) {
799         if (this._disabledImage === disabledImage)
800             return;
801 
802         if (disabledImage) {
803             this.addChild(disabledImage, 0, cc.DISABLE_TAG);
804             disabledImage.anchorX = 0;
805             disabledImage.anchorY = 0;
806         }
807 
808         if (this._disabledImage)
809             this.removeChild(this._disabledImage, true);
810 
811         this._disabledImage = disabledImage;
812         this._updateImagesVisibility();
813     },
814 
815     /**
816      * initializes cc.MenuItemSprite with a cc.Sprite
817      * @param {cc.Node} normalSprite
818      * @param {cc.Node} selectedSprite
819      * @param {cc.Node} disabledSprite
820      * @param {function|String} callback
821      * @param {cc.Node} target
822      * @return {Boolean}
823      */
824     initWithNormalSprite: function (normalSprite, selectedSprite, disabledSprite, callback, target) {
825         this.initWithCallback(callback, target);
826         this.setNormalImage(normalSprite);
827         this.setSelectedImage(selectedSprite);
828         this.setDisabledImage(disabledSprite);
829         var locNormalImage = this._normalImage;
830         if (locNormalImage) {
831             this.width = locNormalImage.width;
832             this.height = locNormalImage.height;
833 
834             if (locNormalImage.textureLoaded && !locNormalImage.textureLoaded()) {
835                 locNormalImage.addEventListener("load", function (sender) {
836                     this.width = sender.width;
837                     this.height = sender.height;
838                     this.setCascadeColorEnabled(true);
839                     this.setCascadeOpacityEnabled(true);
840                 }, this);
841             }
842         }
843         this.setCascadeColorEnabled(true);
844         this.setCascadeOpacityEnabled(true);
845         return true;
846     },
847 
848     /**
849      * menu item is selected (runs callback)
850      */
851     selected: function () {
852         cc.MenuItem.prototype.selected.call(this);
853         if (this._normalImage) {
854             if (this._disabledImage)
855                 this._disabledImage.visible = false;
856 
857             if (this._selectedImage) {
858                 this._normalImage.visible = false;
859                 this._selectedImage.visible = true;
860             } else
861                 this._normalImage.visible = true;
862         }
863     },
864 
865     /**
866      * menu item goes back to unselected state
867      */
868     unselected: function () {
869         cc.MenuItem.prototype.unselected.call(this);
870         if (this._normalImage) {
871             this._normalImage.visible = true;
872 
873             if (this._selectedImage)
874                 this._selectedImage.visible = false;
875 
876             if (this._disabledImage)
877                 this._disabledImage.visible = false;
878         }
879     },
880 
881     /**
882      * set cc.MenuItemSprite  enable to receive the touch event
883      * @param {Boolean} bEnabled
884      */
885     setEnabled: function (bEnabled) {
886         if (this._enabled !== bEnabled) {
887             cc.MenuItem.prototype.setEnabled.call(this, bEnabled);
888             this._updateImagesVisibility();
889         }
890     },
891 
892     _updateImagesVisibility: function () {
893         var locNormalImage = this._normalImage, locSelImage = this._selectedImage, locDisImage = this._disabledImage;
894         if (this._enabled) {
895             if (locNormalImage)
896                 locNormalImage.visible = true;
897             if (locSelImage)
898                 locSelImage.visible = false;
899             if (locDisImage)
900                 locDisImage.visible = false;
901         } else {
902             if (locDisImage) {
903                 if (locNormalImage)
904                     locNormalImage.visible = false;
905                 if (locSelImage)
906                     locSelImage.visible = false;
907                 if (locDisImage)
908                     locDisImage.visible = true;
909             } else {
910                 if (locNormalImage)
911                     locNormalImage.visible = true;
912                 if (locSelImage)
913                     locSelImage.visible = false;
914             }
915         }
916     }
917 });
918 
919 var _p = cc.MenuItemSprite.prototype;
920 
921 // Extended properties
922 /** @expose */
923 _p.normalImage;
924 cc.defineGetterSetter(_p, "normalImage", _p.getNormalImage, _p.setNormalImage);
925 /** @expose */
926 _p.selectedImage;
927 cc.defineGetterSetter(_p, "selectedImage", _p.getSelectedImage, _p.setSelectedImage);
928 /** @expose */
929 _p.disabledImage;
930 cc.defineGetterSetter(_p, "disabledImage", _p.getDisabledImage, _p.setDisabledImage);
931 
932 /**
933  * create a menu item from sprite
934  * @deprecated since v3.0 please use new cc.MenuItemSprite(normalSprite, selectedSprite, three, four, five) instead
935  * @param {Image} normalSprite normal state image
936  * @param {Image|Null} selectedSprite selected state image
937  * @param {Image|cc.Node|Null} three disabled state image OR target node
938  * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
939  * @param {String|function|Null} five callback function name in string or actual function
940  * @return {cc.MenuItemSprite}
941  */
942 cc.MenuItemSprite.create = function (normalSprite, selectedSprite, three, four, five) {
943     return new cc.MenuItemSprite(normalSprite, selectedSprite, three, four, five || undefined);
944 };
945 
946 /**
947  * cc.MenuItemImage accepts images as items.<br/>
948  * The images has 3 different states:<br/>
949  * - unselected image<br/>
950  * - selected image<br/>
951  * - disabled image<br/>
952  * <br/>
953  * For best results try that all images are of the same size<br/>
954  * @class
955  * @extends cc.MenuItemSprite
956  * @param {string|null} normalImage
957  * @param {string|null} selectedImage
958  * @param {string|null} disabledImage
959  * @param {function|string|null} callback
960  * @param {cc.Node|null} target
961  * @example
962  * var menuItem = new cc.MenuItemImage(normalImage, selectedImage, three, four, five);
963  */
964 cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{
965 
966     /**
967      * Constructor of cc.MenuItemImage
968      * @param {string|null} normalImage
969      * @param {string|null} selectedImage
970      * @param {string|null} disabledImage
971      * @param {function|string|null} callback
972      * @param {cc.Node|null} target
973      */
974     ctor: function (normalImage, selectedImage, three, four, five) {
975         var normalSprite = null,
976             selectedSprite = null,
977             disabledSprite = null,
978             callback = null,
979             target = null;
980 
981         if (normalImage === undefined) {
982             cc.MenuItemSprite.prototype.ctor.call(this);
983         }
984         else {
985             normalSprite = new cc.Sprite(normalImage);
986             selectedImage &&
987             (selectedSprite = new cc.Sprite(selectedImage));
988             if (four === undefined) {
989                 callback = three;
990             }
991             else if (five === undefined) {
992                 callback = three;
993                 target = four;
994             }
995             else if (five) {
996                 disabledSprite = new cc.Sprite(three);
997                 callback = four;
998                 target = five;
999             }
1000             cc.MenuItemSprite.prototype.ctor.call(this, normalSprite, selectedSprite, disabledSprite, callback, target);
1001         }
1002     },
1003 
1004     /**
1005      * sets the sprite frame for the normal image
1006      * @param {cc.SpriteFrame} frame
1007      */
1008     setNormalSpriteFrame: function (frame) {
1009         this.setNormalImage(new cc.Sprite(frame));
1010     },
1011 
1012     /**
1013      * sets the sprite frame for the selected image
1014      * @param {cc.SpriteFrame} frame
1015      */
1016     setSelectedSpriteFrame: function (frame) {
1017         this.setSelectedImage(new cc.Sprite(frame));
1018     },
1019 
1020     /**
1021      * sets the sprite frame for the disabled image
1022      * @param {cc.SpriteFrame} frame
1023      */
1024     setDisabledSpriteFrame: function (frame) {
1025         this.setDisabledImage(new cc.Sprite(frame));
1026     },
1027 
1028     /**
1029      * initializes a cc.MenuItemImage
1030      * @param {string|null} normalImage
1031      * @param {string|null} selectedImage
1032      * @param {string|null} disabledImage
1033      * @param {function|string|null} callback
1034      * @param {cc.Node|null} target
1035      * @returns {boolean}
1036      */
1037     initWithNormalImage: function (normalImage, selectedImage, disabledImage, callback, target) {
1038         var normalSprite = null;
1039         var selectedSprite = null;
1040         var disabledSprite = null;
1041 
1042         if (normalImage) {
1043             normalSprite = new cc.Sprite(normalImage);
1044         }
1045         if (selectedImage) {
1046             selectedSprite = new cc.Sprite(selectedImage);
1047         }
1048         if (disabledImage) {
1049             disabledSprite = new cc.Sprite(disabledImage);
1050         }
1051         return this.initWithNormalSprite(normalSprite, selectedSprite, disabledSprite, callback, target);
1052     }
1053 });
1054 
1055 /**
1056  * creates a new menu item image
1057  * @deprecated since v3.0, please use new cc.MenuItemImage(normalImage, selectedImage, three, four, five) instead.
1058  * @param {String} normalImage file name for normal state
1059  * @param {String} selectedImage image for selected state
1060  * @param {String|cc.Node} three Disabled image OR callback function
1061  * @param {String|function|Null} [four] callback function, either name in string or pass the whole function OR the target
1062  * @param {cc.Node|String|function|Null} [five] cc.Node target to run callback when clicked
1063  * @return {cc.MenuItemImage}
1064  */
1065 cc.MenuItemImage.create = function (normalImage, selectedImage, three, four, five) {
1066     return new cc.MenuItemImage(normalImage, selectedImage, three, four, five);
1067 };
1068 
1069 
1070 /**
1071  * A simple container class that "toggles" it's inner items<br/>
1072  * The inner items can be any MenuItem
1073  * @class
1074  * @extends cc.MenuItem
1075  *
1076  * @property {Array}    subItems        - Sub items
1077  * @property {Number}   selectedIndex   - Index of selected sub item
1078  *
1079  *@example
1080  * // Example
1081  * //create a toggle item with 2 menu items (which you can then toggle between them later)
1082  * var toggler = new cc.MenuItemToggle( new cc.MenuItemFont("On"), new cc.MenuItemFont("Off"), this.callback, this)
1083  * //Note: the first param is the target, the second is the callback function, afterwards, you can pass in any number of menuitems
1084  *
1085  * //if you pass only 1 variable, then it must be a cc.MenuItem
1086  * var notYetToggler = new cc.MenuItemToggle(cc.MenuItemFont("On"));//it is useless right now, until you add more stuff to it
1087  * notYetToggler.addSubItem(new cc.MenuItemFont("Off"));
1088  * //this is useful for constructing a toggler without a callback function (you wish to control the behavior from somewhere else)
1089  */
1090 cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{
1091     subItems: null,
1092 
1093     _selectedIndex: 0,
1094     _opacity: null,
1095     _color: null,
1096 
1097     /**
1098      * Constructor of cc.MenuItemToggle
1099     */
1100     ctor: function (/*Multiple arguments follow*/) {
1101 
1102         cc.MenuItem.prototype.ctor.call(this);
1103         this._selectedIndex = 0;
1104         this.subItems = [];
1105         this._opacity = 0;
1106         this._color = cc.color.WHITE;
1107 
1108         if(arguments.length > 0)
1109             this.initWithItems(Array.prototype.slice.apply(arguments));
1110 
1111     },
1112 
1113     /**
1114      * return the opacity of cc.MenuItemToggle
1115      * @return {Number}
1116      */
1117     getOpacity: function () {
1118         return this._opacity;
1119     },
1120 
1121     /**
1122      * set the opacity for cc.MenuItemToggle
1123      * @param {Number} opacity
1124      */
1125     setOpacity: function (opacity) {
1126         this._opacity = opacity;
1127         if (this.subItems && this.subItems.length > 0) {
1128             for (var it = 0; it < this.subItems.length; it++) {
1129                 this.subItems[it].opacity = opacity;
1130             }
1131         }
1132         this._color.a = opacity;
1133     },
1134 
1135     /**
1136      * return the color of cc.MenuItemToggle
1137      * @return {cc.Color}
1138      */
1139     getColor: function () {
1140         var locColor = this._color;
1141         return cc.color(locColor.r, locColor.g, locColor.b, locColor.a);
1142     },
1143 
1144     /**
1145      * set the color for cc.MenuItemToggle
1146      * @param {cc.Color} Color
1147      */
1148     setColor: function (color) {
1149         var locColor = this._color;
1150         locColor.r = color.r;
1151         locColor.g = color.g;
1152         locColor.b = color.b;
1153 
1154         if (this.subItems && this.subItems.length > 0) {
1155             for (var it = 0; it < this.subItems.length; it++) {
1156                 this.subItems[it].setColor(color);
1157             }
1158         }
1159 
1160         if (color.a !== undefined && !color.a_undefined) {
1161             this.setOpacity(color.a);
1162         }
1163     },
1164 
1165     /**
1166      * return the index of selected
1167      * @return {Number}
1168      */
1169     getSelectedIndex: function () {
1170         return this._selectedIndex;
1171     },
1172 
1173     /**
1174      * set the seleceted index for cc.MenuItemToggle
1175      * @param {Number} SelectedIndex
1176      */
1177     setSelectedIndex: function (SelectedIndex) {
1178         if (SelectedIndex !== this._selectedIndex) {
1179             this._selectedIndex = SelectedIndex;
1180             var currItem = this.getChildByTag(cc.CURRENT_ITEM);
1181             if (currItem)
1182                 currItem.removeFromParent(false);
1183 
1184             var item = this.subItems[this._selectedIndex];
1185             this.addChild(item, 0, cc.CURRENT_ITEM);
1186             var w = item.width, h = item.height;
1187             this.width = w;
1188             this.height = h;
1189             item.setPosition(w / 2, h / 2);
1190         }
1191     },
1192 
1193     /**
1194      * similar to get children,return the sumItem array.
1195      * @return {Array}
1196      */
1197     getSubItems: function () {
1198         return this.subItems;
1199     },
1200 
1201     /**
1202      * set the subitem for cc.MenuItemToggle
1203      * @param {cc.MenuItem} subItems
1204      */
1205     setSubItems: function (subItems) {
1206         this.subItems = subItems;
1207     },
1208 
1209     /**
1210      * initializes a cc.MenuItemToggle with items
1211      * @param {cc.MenuItem} args[0...last-2] the rest in the array are cc.MenuItems
1212      * @param {function|String} args[last-1] the second item in the args array is the callback
1213      * @param {cc.Node} args[last] the first item in the args array is a target
1214      * @return {Boolean}
1215      */
1216     initWithItems: function (args) {
1217         var l = args.length;
1218         // passing callback.
1219         if (cc.isFunction(args[args.length - 2])) {
1220             this.initWithCallback(args[args.length - 2], args[args.length - 1]);
1221             l = l - 2;
1222         } else if (cc.isFunction(args[args.length - 1])) {
1223             this.initWithCallback(args[args.length - 1], null);
1224             l = l - 1;
1225         } else {
1226             this.initWithCallback(null, null);
1227         }
1228 
1229         var locSubItems = this.subItems;
1230         locSubItems.length = 0;
1231         for (var i = 0; i < l; i++) {
1232             if (args[i])
1233                 locSubItems.push(args[i]);
1234         }
1235         this._selectedIndex = cc.UINT_MAX;
1236         this.setSelectedIndex(0);
1237 
1238         this.setCascadeColorEnabled(true);
1239         this.setCascadeOpacityEnabled(true);
1240 
1241         return true;
1242     },
1243 
1244     /**
1245      * add the subitem for cc.MenuItemToggle
1246      * @param {cc.MenuItem} item
1247      */
1248     addSubItem: function (item) {
1249         this.subItems.push(item);
1250     },
1251 
1252     /**
1253      * activate the menu item
1254      */
1255     activate: function () {
1256         // update index
1257         if (this._enabled) {
1258             var newIndex = (this._selectedIndex + 1) % this.subItems.length;
1259             this.setSelectedIndex(newIndex);
1260         }
1261         cc.MenuItem.prototype.activate.call(this);
1262     },
1263 
1264     /**
1265      * menu item is selected (runs callback)
1266      */
1267     selected: function () {
1268         cc.MenuItem.prototype.selected.call(this);
1269         this.subItems[this._selectedIndex].selected();
1270     },
1271 
1272     /**
1273      * menu item goes back to unselected state
1274      */
1275     unselected: function () {
1276         cc.MenuItem.prototype.unselected.call(this);
1277         this.subItems[this._selectedIndex].unselected();
1278     },
1279 
1280     /**
1281      * set the enable status for cc.MenuItemToggle
1282      * @param {Boolean} enabled
1283      */
1284     setEnabled: function (enabled) {
1285         if (this._enabled !== enabled) {
1286             cc.MenuItem.prototype.setEnabled.call(this, enabled);
1287             var locItems = this.subItems;
1288             if (locItems && locItems.length > 0) {
1289                 for (var it = 0; it < locItems.length; it++)
1290                     locItems[it].enabled = enabled;
1291             }
1292         }
1293     },
1294 
1295     /**
1296      * returns the selected item   (deprecated in -x, please use getSelectedItem instead.)
1297      * @return {cc.MenuItem}
1298      */
1299     selectedItem: function () {
1300         return this.subItems[this._selectedIndex];
1301     },
1302 
1303     /**
1304      * returns the selected item.
1305      * @return {cc.MenuItem}
1306      */
1307     getSelectedItem: function() {
1308         return this.subItems[this._selectedIndex];
1309     },
1310 
1311     /**
1312      * * <p>
1313      *     Event callback that is invoked every time when cc.MenuItemToggle enters the 'stage'.                                   <br/>
1314      *     If the cc.MenuItemToggle enters the 'stage' with a transition, this event is called when the transition starts.        <br/>
1315      *     During onEnter you can't access a "sister/brother" node.                                                    <br/>
1316      *     If you override onEnter, you must call its parent's onEnter function with this._super().
1317      * </p>
1318      */
1319     onEnter: function () {
1320         cc.Node.prototype.onEnter.call(this);
1321         this.setSelectedIndex(this._selectedIndex);
1322     }
1323 });
1324 
1325 var _p = cc.MenuItemToggle.prototype;
1326 
1327 // Extended properties
1328 /** @expose */
1329 _p.selectedIndex;
1330 cc.defineGetterSetter(_p, "selectedIndex", _p.getSelectedIndex, _p.setSelectedIndex);
1331 
1332 
1333 /**
1334  * create a simple container class that "toggles" it's inner items<br/>
1335  * The inner items can be any MenuItem
1336  * @deprecated since v3.0 please use new cc.MenuItemToggle(params) instead
1337  * @return {cc.MenuItemToggle}
1338  * @example
1339  */
1340 cc.MenuItemToggle.create = function (/*Multiple arguments follow*/) {
1341     if ((arguments.length > 0) && (arguments[arguments.length - 1] == null))
1342         cc.log("parameters should not be ending with null in Javascript");
1343     var ret = new cc.MenuItemToggle();
1344     ret.initWithItems(Array.prototype.slice.apply(arguments));
1345     return ret;
1346 };
1347