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