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(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(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(0, 0);
627         }
628         if (this._normalImage) {
629             this.removeChild(this._normalImage, true);
630         }
631 
632         this._normalImage = normalImage;
633         this.setContentSize(this._normalImage.getContentSize());
634         this._updateImagesVisibility();
635 
636         if (normalImage.textureLoaded && !normalImage.textureLoaded()) {
637             normalImage.addLoadedEventListener(function (sender) {
638                 this.setContentSize(sender.getContentSize());
639             }, this);
640         }
641     },
642 
643     /**
644      * @return {cc.Sprite}
645      */
646     getSelectedImage:function () {
647         return this._selectedImage;
648     },
649 
650     /**
651      * @param {cc.Sprite} selectedImage
652      */
653     setSelectedImage:function (selectedImage) {
654         if (this._selectedImage == selectedImage)
655             return;
656 
657         if (selectedImage) {
658             this.addChild(selectedImage, 0, cc.SELECTED_TAG);
659             selectedImage.setAnchorPoint(0, 0);
660         }
661 
662         if (this._selectedImage) {
663             this.removeChild(this._selectedImage, true);
664         }
665 
666         this._selectedImage = selectedImage;
667         this._updateImagesVisibility();
668     },
669 
670     /**
671      * @return {cc.Sprite}
672      */
673     getDisabledImage:function () {
674         return this._disabledImage;
675     },
676 
677     /**
678      * @param {cc.Sprite} disabledImage
679      */
680     setDisabledImage:function (disabledImage) {
681         if (this._disabledImage == disabledImage)
682             return;
683 
684         if (disabledImage) {
685             this.addChild(disabledImage, 0, cc.DISABLE_TAG);
686             disabledImage.setAnchorPoint(0, 0);
687         }
688 
689         if (this._disabledImage)
690             this.removeChild(this._disabledImage, true);
691 
692         this._disabledImage = disabledImage;
693         this._updateImagesVisibility();
694     },
695 
696     /**
697      * @param {cc.Node} normalSprite
698      * @param {cc.Node} selectedSprite
699      * @param {cc.Node} disabledSprite
700      * @param {function|String} callback
701      * @param {cc.Node} target
702      * @return {Boolean}
703      */
704     initWithNormalSprite:function (normalSprite, selectedSprite, disabledSprite, callback, target) {
705         this.initWithCallback(callback, target);
706         this.setNormalImage(normalSprite);
707         this.setSelectedImage(selectedSprite);
708         this.setDisabledImage(disabledSprite);
709         var locNormalImage = this._normalImage;
710         if (locNormalImage) {
711             this.setContentSize(locNormalImage.getContentSize());
712 
713             if (locNormalImage.textureLoaded && !locNormalImage.textureLoaded()) {
714                 locNormalImage.addLoadedEventListener(function (sender) {
715                     this.setContentSize(sender.getContentSize());
716                     this.setCascadeColorEnabled(true);
717                     this.setCascadeOpacityEnabled(true);
718                 }, this);
719             }
720         }
721         this.setCascadeColorEnabled(true);
722         this.setCascadeOpacityEnabled(true);
723         return true;
724     },
725 
726     /**
727      * @param {cc.Color3B} color
728      */
729     setColor:function (color) {
730         this._normalImage.setColor(color);
731 
732         if (this._selectedImage)
733             this._selectedImage.setColor(color);
734 
735         if (this._disabledImage)
736             this._disabledImage.setColor(color);
737     },
738 
739     /**
740      * @return {cc.Color3B}
741      */
742     getColor:function () {
743         return this._normalImage.getColor();
744     },
745 
746     /**
747      * @param {Number} opacity 0 - 255
748      */
749     setOpacity:function (opacity) {
750         this._normalImage.setOpacity(opacity);
751 
752         if (this._selectedImage)
753             this._selectedImage.setOpacity(opacity);
754 
755         if (this._disabledImage)
756             this._disabledImage.setOpacity(opacity);
757     },
758 
759     /**
760      * @return {Number} opacity from 0 - 255
761      */
762     getOpacity:function () {
763         return this._normalImage.getOpacity();
764     },
765 
766     /**
767      * menu item is selected (runs callback)
768      */
769     selected:function () {
770         cc.MenuItem.prototype.selected.call(this);
771         if (this._normalImage) {
772             if (this._disabledImage)
773                 this._disabledImage.setVisible(false);
774 
775             if (this._selectedImage) {
776                 this._normalImage.setVisible(false);
777                 this._selectedImage.setVisible(true);
778             } else
779                 this._normalImage.setVisible(true);
780         }
781     },
782 
783     /**
784      * menu item goes back to unselected state
785      */
786     unselected:function () {
787         cc.MenuItem.prototype.unselected.call(this);
788         if (this._normalImage) {
789             this._normalImage.setVisible(true);
790 
791             if (this._selectedImage)
792                 this._selectedImage.setVisible(false);
793 
794             if (this._disabledImage)
795                 this._disabledImage.setVisible(false);
796         }
797     },
798 
799     /**
800      * @param {Boolean} bEnabled
801      */
802     setEnabled:function (bEnabled) {
803         if (this._isEnabled != bEnabled) {
804             cc.MenuItem.prototype.setEnabled.call(this, bEnabled);
805             this._updateImagesVisibility();
806         }
807     },
808 
809     _updateImagesVisibility:function () {
810         var locNormalImage = this._normalImage, locSelImage = this._selectedImage, locDisImage = this._disabledImage;
811         if (this._isEnabled) {
812             if (locNormalImage)
813                 locNormalImage.setVisible(true);
814             if (locSelImage)
815                 locSelImage.setVisible(false);
816             if (locDisImage)
817                 locDisImage.setVisible(false);
818         } else {
819             if (locDisImage) {
820                 if (locNormalImage)
821                     locNormalImage.setVisible(false);
822                 if (locSelImage)
823                     locSelImage.setVisible(false);
824                 if (locDisImage)
825                     locDisImage.setVisible(true);
826             } else {
827                 if (locNormalImage)
828                     locNormalImage.setVisible(true);
829                 if (locSelImage)
830                     locSelImage.setVisible(false);
831             }
832         }
833     }
834 });
835 
836 /**
837  * create a menu item from sprite
838  * @param {Image} normalSprite normal state image
839  * @param {Image|Null} selectedSprite selected state image
840  * @param {Image|cc.Node|Null} three disabled state image OR target node
841  * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
842  * @param {String|function|Null} five callback function name in string or actual function
843  * @return {cc.MenuItemSprite}
844  * @example
845  * // Example
846  * var item = cc.MenuItemSprite.create(normalImage)//create a menu item from a sprite with no functionality
847  *
848  * var item = cc.MenuItemSprite.create(normalImage, selectedImage)//create a menu Item, nothing will happen when clicked
849  *
850  * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, disabledImage)//same above, but with disabled state image
851  *
852  * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, 'callback', targetNode)//create a menu item, when clicked runs targetNode.callback()
853  *
854  * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, disabledImage, targetNode.callback, targetNode)
855  * //same as above, but with disabled image, and passing in callback function
856  */
857 cc.MenuItemSprite.create = function (normalSprite, selectedSprite, three, four, five) {
858     var len = arguments.length;
859     normalSprite = arguments[0];
860     selectedSprite = arguments[1];
861     var disabledImage, target, callback;
862     var ret = new cc.MenuItemSprite();
863     //when you send 4 arguments, five is undefined
864     if (len == 5) {
865         disabledImage = arguments[2];
866         callback = arguments[3];
867         target = arguments[4];
868     } else if (len == 4 && typeof arguments[3] === "function") {
869         disabledImage = arguments[2];
870         callback = arguments[3];
871     } else if (len == 4 && typeof arguments[2] === "function") {
872         target = arguments[3];
873         callback = arguments[2];
874     } else if (len <= 2) {
875         disabledImage = arguments[2];
876     }
877     ret.initWithNormalSprite(normalSprite, selectedSprite, disabledImage,  callback, target);
878     return ret;
879 };
880 
881 /**
882  * cc.MenuItemImage accepts images as items.<br/>
883  * The images has 3 different states:<br/>
884  * - unselected image<br/>
885  * - selected image<br/>
886  * - disabled image<br/>
887  * <br/>
888  * For best results try that all images are of the same size<br/>
889  * @class
890  * @extends cc.MenuItemSprite
891  */
892 cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{
893     /**
894      * sets the sprite frame for the normal image
895      * @param {cc.SpriteFrame} frame
896      */
897     setNormalSpriteFrame:function (frame) {
898         this.setNormalImage(cc.Sprite.createWithSpriteFrame(frame));
899     },
900 
901     /**
902      * sets the sprite frame for the selected image
903      * @param {cc.SpriteFrame} frame
904      */
905     setSelectedSpriteFrame:function (frame) {
906         this.setSelectedImage(cc.Sprite.createWithSpriteFrame(frame));
907     },
908 
909     /**
910      * sets the sprite frame for the disabled image
911      * @param {cc.SpriteFrame} frame
912      */
913     setDisabledSpriteFrame:function (frame) {
914         this.setDisabledImage(cc.Sprite.createWithSpriteFrame(frame));
915     },
916 
917     /**
918      * @param {string|null} normalImage
919      * @param {string|null} selectedImage
920      * @param {string|null} disabledImage
921      * @param {function|string|null} callback
922      * @param {cc.Node|null} target
923      * @returns {boolean}
924      */
925     initWithNormalImage:function (normalImage, selectedImage, disabledImage, callback, target) {
926         var normalSprite = null;
927         var selectedSprite = null;
928         var disabledSprite = null;
929 
930         if (normalImage) {
931             normalSprite = cc.Sprite.create(normalImage);
932         }
933         if (selectedImage) {
934             selectedSprite = cc.Sprite.create(selectedImage);
935         }
936         if (disabledImage) {
937             disabledSprite = cc.Sprite.create(disabledImage);
938         }
939         return this.initWithNormalSprite(normalSprite, selectedSprite, disabledSprite, callback, target);
940     }
941 });
942 
943 /**
944  * creates a new menu item image
945  * @param {String} normalImage file name for normal state
946  * @param {String} selectedImage image for selected state
947  * @param {String|cc.Node} three Disabled image OR callback function
948  * @param {String|function|Null} [four] callback function, either name in string or pass the whole function OR the target
949  * @param {cc.Node|String|function|Null} [five] cc.Node target to run callback when clicked
950  * @return {cc.MenuItemImage}
951  * @example
952  * // Example
953  * //create a dom menu item with normal and selected state, when clicked it will run the run function from gameScene object
954  * var item = cc.MenuItemImage.create('normal.png', 'selected.png', 'run', gameScene)
955  *
956  * //same as above, but pass in the actual function and disabled image
957  * var item = cc.MenuItemImage.create('normal.png', 'selected.png', 'disabled.png', gameScene.run, gameScene)
958  */
959 cc.MenuItemImage.create = function (normalImage, selectedImage, three, four, five) {
960     if (arguments.length == 0) {
961         return cc.MenuItemImage.create(null, null, null, null, null);
962     }
963     if (arguments.length == 3)  {
964         return cc.MenuItemImage.create(normalImage, selectedImage, null, three, null);
965     }
966     if (arguments.length == 4) {
967         return cc.MenuItemImage.create(normalImage, selectedImage, null, three, four);
968     }
969     var ret = new cc.MenuItemImage();
970     if (ret.initWithNormalImage(normalImage, selectedImage, three, four, five))
971         return ret;
972     return null;
973 };
974 
975 
976 /**
977  * A simple container class that "toggles" it's inner items<br/>
978  * The inner items can be any MenuItem
979  * @class
980  * @extends cc.MenuItem
981  */
982 cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{
983     _selectedIndex:0,
984     _subItems:null,
985     _opacity:null,
986     _color:null,
987 
988     ctor: function(){
989         cc.MenuItem.prototype.ctor.call(this);
990         this._selectedIndex = 0;
991         this._subItems = [];
992         this._opacity = 0;
993         this._color = cc.white();
994     },
995 
996     /**
997      * @return {Number}
998      */
999     getOpacity:function () {
1000         return this._opacity;
1001     },
1002 
1003     /**
1004      * @param {Number} Opacity
1005      */
1006     setOpacity:function (Opacity) {
1007         this._opacity = Opacity;
1008         if (this._subItems && this._subItems.length > 0) {
1009             for (var it = 0; it < this._subItems.length; it++) {
1010                 this._subItems[it].setOpacity(Opacity);
1011             }
1012         }
1013     },
1014 
1015     /**
1016      * @return {cc.Color3B}
1017      */
1018     getColor:function () {
1019         return this._color;
1020     },
1021 
1022     /**
1023      * @param {cc.Color3B} Color
1024      */
1025     setColor:function (Color) {
1026         this._color = Color;
1027         if (this._subItems && this._subItems.length > 0) {
1028             for (var it = 0; it < this._subItems.length; it++) {
1029                 this._subItems[it].setColor(Color);
1030             }
1031         }
1032     },
1033 
1034     /**
1035      * @return {Number}
1036      */
1037     getSelectedIndex:function () {
1038         return this._selectedIndex;
1039     },
1040 
1041     /**
1042      * @param {Number} SelectedIndex
1043      */
1044     setSelectedIndex:function (SelectedIndex) {
1045         if (SelectedIndex != this._selectedIndex) {
1046             this._selectedIndex = SelectedIndex;
1047             var currItem = this.getChildByTag(cc.CURRENT_ITEM);
1048             if (currItem)
1049                 currItem.removeFromParent(false);
1050 
1051             var item = this._subItems[this._selectedIndex];
1052             this.addChild(item, 0, cc.CURRENT_ITEM);
1053             var s = item.getContentSize();
1054             this.setContentSize(s);
1055             item.setPosition(s.width / 2, s.height / 2);
1056         }
1057     },
1058 
1059     /**
1060      * similar to get children
1061      * @return {cc.MenuItem}
1062      */
1063     getSubItems:function () {
1064         return this._subItems;
1065     },
1066 
1067     /**
1068      * @param {cc.MenuItem} SubItems
1069      */
1070     setSubItems:function (SubItems) {
1071         this._subItems = SubItems;
1072     },
1073 
1074     /**
1075      * @param {cc.MenuItem} args[0...last-2] the rest in the array are cc.MenuItems
1076      * @param {function|String} args[last-1] the second item in the args array is the callback
1077      * @param {cc.Node} args[last] the first item in the args array is a target
1078      * @return {Boolean}
1079      */
1080     initWithItems:function (args) {
1081         var l =  args.length;
1082         // passing callback.
1083         if (typeof args[args.length-2] === 'function') {
1084             this.initWithCallback( args[args.length-2], args[args.length-1] );
1085             l = l-2;
1086         } else if(typeof args[args.length-1] === 'function'){
1087             this.initWithCallback( args[args.length-1], null );
1088             l = l-1;
1089         } else {
1090             this.initWithCallback(null, null);
1091         }
1092 
1093         var locSubItems = this._subItems;
1094         locSubItems.length = 0;
1095         for (var i = 0; i < l; i++) {
1096             if (args[i])
1097                 locSubItems.push(args[i]);
1098         }
1099         this._selectedIndex = cc.UINT_MAX;
1100         this.setSelectedIndex(0);
1101 
1102         this.setCascadeColorEnabled(true);
1103         this.setCascadeOpacityEnabled(true);
1104 
1105         return true;
1106     },
1107 
1108     /**
1109      * @param {cc.MenuItem} item
1110      */
1111     addSubItem:function (item) {
1112         this._subItems.push(item);
1113     },
1114 
1115     /**
1116      * activate the menu item
1117      */
1118     activate:function () {
1119         // update index
1120         if (this._isEnabled) {
1121             var newIndex = (this._selectedIndex + 1) % this._subItems.length;
1122             this.setSelectedIndex(newIndex);
1123         }
1124         cc.MenuItem.prototype.activate.call(this);
1125     },
1126 
1127     /**
1128      * menu item is selected (runs callback)
1129      */
1130     selected:function () {
1131         cc.MenuItem.prototype.selected.call(this);
1132         this._subItems[this._selectedIndex].selected();
1133     },
1134 
1135     /**
1136      * menu item goes back to unselected state
1137      */
1138     unselected:function () {
1139         cc.MenuItem.prototype.unselected.call(this);
1140         this._subItems[this._selectedIndex].unselected();
1141     },
1142 
1143     /**
1144      * @param {Boolean} enabled
1145      */
1146     setEnabled:function (enabled) {
1147         if (this._isEnabled != enabled) {
1148             cc.MenuItem.prototype.setEnabled.call(this, enabled);
1149             var locItems = this._subItems;
1150             if (locItems && locItems.length > 0) {
1151                 for (var it = 0; it < locItems.length; it++)
1152                     locItems[it].setEnabled(enabled);
1153             }
1154         }
1155     },
1156 
1157     /**
1158      * returns the selected item
1159      * @return {cc.MenuItem}
1160      */
1161     selectedItem:function () {
1162         return this._subItems[this._selectedIndex];
1163     },
1164 
1165     onEnter:function () {
1166         cc.Node.prototype.onEnter.call(this);
1167         this.setSelectedIndex(this._selectedIndex);
1168     }
1169 });
1170 
1171 /**
1172  * create a simple container class that "toggles" it's inner items<br/>
1173  * The inner items can be any MenuItem
1174  * @return {cc.MenuItemToggle}
1175  * @example
1176  * // Example
1177  *
1178  * //create a toggle item with 2 menu items (which you can then toggle between them later)
1179  * var toggler = cc.MenuItemToggle.create( cc.MenuItemFont.create("On"), cc.MenuItemFont.create("Off"), this.callback, this)
1180  * //Note: the first param is the target, the second is the callback function, afterwards, you can pass in any number of menuitems
1181  *
1182  * //if you pass only 1 variable, then it must be a cc.MenuItem
1183  * var notYetToggler = cc.MenuItemToggle.create(cc.MenuItemFont.create("On"));//it is useless right now, until you add more stuff to it
1184  * notYetToggler.addSubItem(cc.MenuItemFont.create("Off"));
1185  * //this is useful for constructing a toggler without a callback function (you wish to control the behavior from somewhere else)
1186  */
1187 cc.MenuItemToggle.create = function (/*Multiple arguments follow*/) {
1188     if((arguments.length > 0) && (arguments[arguments.length-1] == null))
1189         cc.log("parameters should not be ending with null in Javascript");
1190     var ret = new cc.MenuItemToggle();
1191     ret.initWithItems(arguments);
1192     return ret;
1193 };
1194