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