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