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