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