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