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