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         cc.Assert(value != null && value.length != 0, "value length must be greater than 0");
420         var label = new cc.LabelAtlas();
421         label.initWithString(value, charMapFile, itemWidth, itemHeight, startCharMap);
422         if (this.initWithLabel(label,  callback, target)) {
423             // do something ?
424         }
425         return true;
426     }
427 });
428 
429 /**
430  * create menu item from string with font
431  * @param {String} value the text to display
432  * @param {String} charMapFile the character map file
433  * @param {Number} itemWidth
434  * @param {Number} itemHeight
435  * @param {String} startCharMap a single character
436  * @param {function|String|Null} [callback=null]
437  * @param {cc.Node|Null} [target=]
438  * @return {cc.MenuItemAtlasFont}
439  * @example
440  * // Example
441  * var item = cc.MenuItemAtlasFont.create('text to display', 'font.fnt', 12, 32, ' ')
442  *
443  * //OR
444  * var item = cc.MenuItemAtlasFont.create('text to display', 'font.fnt', 12, 32, ' ',  game.run, game)
445  */
446 cc.MenuItemAtlasFont.create = function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) {
447     var ret = new cc.MenuItemAtlasFont();
448     ret.initWithString(value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target);
449     return ret;
450 };
451 
452 /**
453  * Helper class that creates a CCMenuItemLabel class with a Label
454  * @class
455  * @extends cc.MenuItemLabel
456  */
457 cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{
458     _fontSize:null,
459     _fontName:null,
460 
461     ctor:function(){
462         cc.MenuItemLabel.prototype.ctor.call(this);
463         this._fontSize = 0;
464         this._fontName = "";
465     },
466 
467     /**
468      * @param {String} value text for the menu item
469      * @param {function|String} callback
470      * @param {cc.Node} target
471      * @return {Boolean}
472      */
473     initWithString:function (value, callback, target) {
474         cc.Assert(value != null && value.length != 0, "Value length must be greater than 0");
475 
476         this._fontName = cc._globalFontName;
477         this._fontSize = cc._globalFontSize;
478 
479         var label = cc.LabelTTF.create(value, this._fontName, this._fontSize);
480         if (this.initWithLabel(label, callback, target)) {
481             // do something ?
482         }
483         return true;
484     },
485 
486     /**
487      * @param {Number} s
488      */
489     setFontSize:function (s) {
490         this._fontSize = s;
491         this._recreateLabel();
492     },
493 
494     /**
495      *
496      * @return {Number}
497      */
498     fontSize:function () {
499         return this._fontSize;
500     },
501 
502     /**
503      * @param {String} name
504      */
505     setFontName:function (name) {
506         this._fontName = name;
507         this._recreateLabel();
508     },
509 
510     /**
511      * @return {String}
512      */
513     fontName:function () {
514         return this._fontName;
515     },
516 
517     _recreateLabel:function () {
518         var label = cc.LabelTTF.create(this._label.getString(),
519             this._fontName, this._fontSize);
520         this.setLabel(label);
521     }
522 });
523 
524 /**
525  * a shared function to set the fontSize for menuitem font
526  * @param {Number} fontSize
527  */
528 cc.MenuItemFont.setFontSize = function (fontSize) {
529     cc._globalFontSize = fontSize;
530 };
531 
532 /**
533  * a shared function to get the font size for menuitem font
534  * @return {Number}
535  */
536 cc.MenuItemFont.fontSize = function () {
537     return cc._globalFontSize;
538 };
539 
540 /**
541  * a shared function to set the fontsize for menuitem font
542  * @param name
543  */
544 cc.MenuItemFont.setFontName = function (name) {
545     if (cc._globalFontNameRelease) {
546         cc._globalFontName = '';
547     }
548     cc._globalFontName = name;
549     cc._globalFontNameRelease = true;
550 };
551 
552 /**
553  * a shared function to get the font name for menuitem font
554  * @return {String}
555  */
556 cc.MenuItemFont.fontName = function () {
557     return cc._globalFontName;
558 };
559 
560 /**
561  * create a menu item from string
562  * @param {String} value the text to display
563  * @param {String|function|Null} callback the callback to run, either in function name or pass in the actual function
564  * @param {cc.Node|Null} target the target to run callback
565  * @return {cc.MenuItemFont}
566  * @example
567  * // Example
568  * var item = cc.MenuItemFont.create("Game start", 'start', Game)
569  * //creates a menu item from string "Game start", and when clicked, it will run Game.start()
570  *
571  * var item = cc.MenuItemFont.create("Game start", game.start, Game)//same as above
572  *
573  * var item = cc.MenuItemFont.create("i do nothing")//create a text menu item that does nothing
574  *
575  * //you can set font size and name before or after
576  * cc.MenuItemFont.setFontName('my Fancy Font');
577  * cc.MenuItemFont.setFontSize(62);
578  */
579 cc.MenuItemFont.create = function (value, callback, target) {
580     var ret = new cc.MenuItemFont();
581     ret.initWithString(value, callback, target);
582     return ret;
583 };
584 
585 
586 /**
587  * CCMenuItemSprite accepts CCNode<CCRGBAProtocol> objects as items.<br/>
588  * The images has 3 different states:<br/>
589  *   - unselected image<br/>
590  *   - selected image<br/>
591  *   - disabled image<br/>
592  * @class
593  * @extends cc.MenuItem
594  */
595 cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{
596     _normalImage:null,
597     _selectedImage:null,
598     _disabledImage:null,
599 
600     ctor: function(){
601         cc.MenuItem.prototype.ctor.call(this);
602         this._normalImage = null;
603         this._selectedImage = null;
604         this._disabledImage = null;
605     },
606 
607     /**
608      * @return {cc.Sprite}
609      */
610     getNormalImage:function () {
611         return this._normalImage;
612     },
613 
614     /**
615      * @param {cc.Sprite} normalImage
616      */
617     setNormalImage:function (normalImage) {
618         if (this._normalImage == normalImage) {
619             return;
620         }
621         if (normalImage) {
622             this.addChild(normalImage, 0, cc.NORMAL_TAG);
623             normalImage.setAnchorPoint(cc.p(0, 0));
624         }
625         if (this._normalImage) {
626             this.removeChild(this._normalImage, true);
627         }
628 
629         this._normalImage = normalImage;
630         if(normalImage.textureLoaded()){
631             this.setContentSize(this._normalImage.getContentSize());
632             this._updateImagesVisibility();
633         } else {
634             normalImage.addLoadedEventListener(function(sender){
635                 this.setContentSize(sender.getContentSize());
636                 this._updateImagesVisibility();
637             }, this);
638         }
639     },
640 
641     /**
642      * @return {cc.Sprite}
643      */
644     getSelectedImage:function () {
645         return this._selectedImage;
646     },
647 
648     /**
649      * @param {cc.Sprite} selectedImage
650      */
651     setSelectedImage:function (selectedImage) {
652         if (this._selectedImage == selectedImage)
653             return;
654 
655         if (selectedImage) {
656             this.addChild(selectedImage, 0, cc.SELECTED_TAG);
657             selectedImage.setAnchorPoint(cc.p(0, 0));
658         }
659 
660         if (this._selectedImage) {
661             this.removeChild(this._selectedImage, true);
662         }
663 
664         this._selectedImage = selectedImage;
665         if(selectedImage.textureLoaded()){
666             this._updateImagesVisibility();
667         } else {
668             selectedImage.addLoadedEventListener(function(sender){
669                 this._updateImagesVisibility();
670             }, this);
671         }
672     },
673 
674     /**
675      * @return {cc.Sprite}
676      */
677     getDisabledImage:function () {
678         return this._disabledImage;
679     },
680 
681     /**
682      * @param {cc.Sprite} disabledImage
683      */
684     setDisabledImage:function (disabledImage) {
685         if (this._disabledImage == disabledImage)
686             return;
687 
688         if (disabledImage) {
689             this.addChild(disabledImage, 0, cc.DISABLE_TAG);
690             disabledImage.setAnchorPoint(cc.p(0, 0));
691         }
692 
693         if (this._disabledImage)
694             this.removeChild(this._disabledImage, true);
695 
696         this._disabledImage = disabledImage;
697         if(disabledImage.textureLoaded()){
698             this._updateImagesVisibility();
699         } else {
700             disabledImage.addLoadedEventListener(function(sender){
701                 this._updateImagesVisibility();
702             }, this);
703         }
704     },
705 
706     /**
707      * @param {cc.Node} normalSprite
708      * @param {cc.Node} selectedSprite
709      * @param {cc.Node} disabledSprite
710      * @param {function|String} callback
711      * @param {cc.Node} target
712      * @return {Boolean}
713      */
714     initWithNormalSprite:function (normalSprite, selectedSprite, disabledSprite, callback, target) {
715         this.initWithCallback(callback, target);
716         this.setNormalImage(normalSprite);
717         this.setSelectedImage(selectedSprite);
718         this.setDisabledImage(disabledSprite);
719         var locNormalImage = this._normalImage;
720         if (locNormalImage){
721             if(locNormalImage.textureLoaded()){
722                 this.setContentSize(locNormalImage.getContentSize());
723                 this.setCascadeColorEnabled(true);
724                 this.setCascadeOpacityEnabled(true);
725             } else{
726                 locNormalImage.addLoadedEventListener(function(sender){
727                     this.setContentSize(sender.getContentSize());
728                     this.setCascadeColorEnabled(true);
729                     this.setCascadeOpacityEnabled(true);
730                 }, this);
731             }
732         }
733 
734 
735         return true;
736     },
737 
738     /**
739      * @param {cc.Color3B} color
740      */
741     setColor:function (color) {
742         this._normalImage.setColor(color);
743 
744         if (this._selectedImage)
745             this._selectedImage.setColor(color);
746 
747         if (this._disabledImage)
748             this._disabledImage.setColor(color);
749     },
750 
751     /**
752      * @return {cc.Color3B}
753      */
754     getColor:function () {
755         return this._normalImage.getColor();
756     },
757 
758     /**
759      * @param {Number} opacity 0 - 255
760      */
761     setOpacity:function (opacity) {
762         this._normalImage.setOpacity(opacity);
763 
764         if (this._selectedImage)
765             this._selectedImage.setOpacity(opacity);
766 
767         if (this._disabledImage)
768             this._disabledImage.setOpacity(opacity);
769     },
770 
771     /**
772      * @return {Number} opacity from 0 - 255
773      */
774     getOpacity:function () {
775         return this._normalImage.getOpacity();
776     },
777 
778     /**
779      * menu item is selected (runs callback)
780      */
781     selected:function () {
782         cc.MenuItem.prototype.selected.call(this);
783         if (this._normalImage) {
784             if (this._disabledImage)
785                 this._disabledImage.setVisible(false);
786 
787             if (this._selectedImage) {
788                 this._normalImage.setVisible(false);
789                 this._selectedImage.setVisible(true);
790             } else
791                 this._normalImage.setVisible(true);
792         }
793     },
794 
795     /**
796      * menu item goes back to unselected state
797      */
798     unselected:function () {
799         cc.MenuItem.prototype.unselected.call(this);
800         if (this._normalImage) {
801             this._normalImage.setVisible(true);
802 
803             if (this._selectedImage)
804                 this._selectedImage.setVisible(false);
805 
806             if (this._disabledImage)
807                 this._disabledImage.setVisible(false);
808         }
809     },
810 
811     /**
812      * @param {Boolean} bEnabled
813      */
814     setEnabled:function (bEnabled) {
815         if (this._isEnabled != bEnabled) {
816             cc.MenuItem.prototype.setEnabled.call(this, bEnabled);
817             this._updateImagesVisibility();
818         }
819     },
820 
821     _updateImagesVisibility:function () {
822         var locNormalImage = this._normalImage, locSelImage = this._selectedImage, locDisImage = this._disabledImage;
823         if (this._isEnabled) {
824             if (locNormalImage)
825                 locNormalImage.setVisible(true);
826             if (locSelImage)
827                 locSelImage.setVisible(false);
828             if (locDisImage)
829                 locDisImage.setVisible(false);
830         } else {
831             if (locDisImage) {
832                 if (locNormalImage)
833                     locNormalImage.setVisible(false);
834                 if (locSelImage)
835                     locSelImage.setVisible(false);
836                 if (locDisImage)
837                     locDisImage.setVisible(true);
838             } else {
839                 if (locNormalImage)
840                     locNormalImage.setVisible(true);
841                 if (locSelImage)
842                     locSelImage.setVisible(false);
843             }
844         }
845     }
846 });
847 
848 /**
849  * create a menu item from sprite
850  * @param {Image} normalSprite normal state image
851  * @param {Image|Null} selectedSprite selected state image
852  * @param {Image|cc.Node|Null} three disabled state image OR target node
853  * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node
854  * @param {String|function|Null} five callback function name in string or actual function
855  * @return {cc.MenuItemSprite}
856  * @example
857  * // Example
858  * var item = cc.MenuItemSprite.create(normalImage)//create a menu item from a sprite with no functionality
859  *
860  * var item = cc.MenuItemSprite.create(normalImage, selectedImage)//create a menu Item, nothing will happen when clicked
861  *
862  * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, disabledImage)//same above, but with disabled state image
863  *
864  * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, 'callback', targetNode)//create a menu item, when clicked runs targetNode.callback()
865  *
866  * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, disabledImage, targetNode.callback, targetNode)
867  * //same as above, but with disabled image, and passing in callback function
868  */
869 cc.MenuItemSprite.create = function (normalSprite, selectedSprite, three, four, five) {
870     var len = arguments.length;
871     normalSprite = arguments[0];
872     selectedSprite = arguments[1];
873     var disabledImage, target, callback;
874     var ret = new cc.MenuItemSprite();
875     //when you send 4 arguments, five is undefined
876     if (len == 5) {
877         disabledImage = arguments[2];
878         callback = arguments[3];
879         target = arguments[4];
880     } else if (len == 4 && typeof arguments[3] === "function") {
881         disabledImage = arguments[2];
882         callback = arguments[3];
883     } else if (len == 4 && typeof arguments[2] === "function") {
884         target = arguments[3];
885         callback = arguments[2];
886     } else if (len <= 2) {
887         disabledImage = arguments[2];
888     }
889     ret.initWithNormalSprite(normalSprite, selectedSprite, disabledImage,  callback, target);
890     return ret;
891 };
892 
893 /**
894  * cc.MenuItemImage accepts images as items.<br/>
895  * The images has 3 different states:<br/>
896  * - unselected image<br/>
897  * - selected image<br/>
898  * - disabled image<br/>
899  * <br/>
900  * For best results try that all images are of the same size<br/>
901  * @class
902  * @extends cc.MenuItemSprite
903  */
904 cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{
905     /**
906      * sets the sprite frame for the normal image
907      * @param {cc.SpriteFrame} frame
908      */
909     setNormalSpriteFrame:function (frame) {
910         this.setNormalImage(cc.Sprite.createWithSpriteFrame(frame));
911     },
912 
913     /**
914      * sets the sprite frame for the selected image
915      * @param {cc.SpriteFrame} frame
916      */
917     setSelectedSpriteFrame:function (frame) {
918         this.setSelectedImage(cc.Sprite.createWithSpriteFrame(frame));
919     },
920 
921     /**
922      * sets the sprite frame for the disabled image
923      * @param {cc.SpriteFrame} frame
924      */
925     setDisabledSpriteFrame:function (frame) {
926         this.setDisabledImage(cc.Sprite.createWithSpriteFrame(frame));
927     },
928 
929     /**
930      * @param {string|null} normalImage
931      * @param {string|null} selectedImage
932      * @param {string|null} disabledImage
933      * @param {function|string|null} callback
934      * @param {cc.Node|null} target
935      * @returns {boolean}
936      */
937     initWithNormalImage:function (normalImage, selectedImage, disabledImage, callback, target) {
938         var normalSprite = null;
939         var selectedSprite = null;
940         var disabledSprite = null;
941 
942         if (normalImage) {
943             normalSprite = cc.Sprite.create(normalImage);
944         }
945         if (selectedImage) {
946             selectedSprite = cc.Sprite.create(selectedImage);
947         }
948         if (disabledImage) {
949             disabledSprite = cc.Sprite.create(disabledImage);
950         }
951         return this.initWithNormalSprite(normalSprite, selectedSprite, disabledSprite, callback, target);
952     }
953 });
954 
955 /**
956  * creates a new menu item image
957  * @param {String} normalImage file name for normal state
958  * @param {String} selectedImage image for selected state
959  * @param {String|cc.Node} three Disabled image OR allback function
960  * @param {String|function|Null} four callback function, either name in string or pass the whole function OR the target
961  * @param {cc.Node|String|function|Null} five cc.Node target to run callback when clicked
962  * @return {cc.MenuItemImage}
963  * @example
964  * // Example
965  * //create a dom menu item with normal and selected state, when clicked it will run the run function from gameScene object
966  * var item = cc.MenuItemImage.create('normal.png', 'selected.png', 'run', gameScene)
967  *
968  * //same as above, but pass in the actual function and disabled image
969  * var item = cc.MenuItemImage.create('normal.png', 'selected.png', 'disabled.png', gameScene.run, gameScene)
970  */
971 cc.MenuItemImage.create = function (normalImage, selectedImage, three, four, five) {
972     if (arguments.length == 0) {
973         return cc.MenuItemImage.create(null, null, null, null, null);
974     }
975     if (arguments.length == 3)  {
976         return cc.MenuItemImage.create(normalImage, selectedImage, null, three, null);
977     }
978     if (arguments.length == 4) {
979         return cc.MenuItemImage.create(normalImage, selectedImage, null, three, four);
980     }
981     var ret = new cc.MenuItemImage();
982     if (ret.initWithNormalImage(normalImage, selectedImage, three, four, five))
983         return ret;
984     return null;
985 };
986 
987 
988 /**
989  * A simple container class that "toggles" it's inner items<br/>
990  * The inner items can be any MenuItem
991  * @class
992  * @extends cc.MenuItem
993  */
994 cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{
995     _selectedIndex:0,
996     _subItems:null,
997     _opacity:null,
998     _color:null,
999 
1000     ctor: function(){
1001         cc.MenuItem.prototype.ctor.call(this);
1002         this._selectedIndex = 0;
1003         this._subItems = [];
1004         this._opacity = 0;
1005         this._color = cc.white();
1006     },
1007 
1008     /**
1009      * @return {Number}
1010      */
1011     getOpacity:function () {
1012         return this._opacity;
1013     },
1014 
1015     /**
1016      * @param {Number} Opacity
1017      */
1018     setOpacity:function (Opacity) {
1019         this._opacity = Opacity;
1020         if (this._subItems && this._subItems.length > 0) {
1021             for (var it = 0; it < this._subItems.length; it++) {
1022                 this._subItems[it].setOpacity(Opacity);
1023             }
1024         }
1025     },
1026 
1027     /**
1028      * @return {cc.Color3B}
1029      */
1030     getColor:function () {
1031         return this._color;
1032     },
1033 
1034     /**
1035      * @param {cc.Color3B} Color
1036      */
1037     setColor:function (Color) {
1038         this._color = Color;
1039         if (this._subItems && this._subItems.length > 0) {
1040             for (var it = 0; it < this._subItems.length; it++) {
1041                 this._subItems[it].setColor(Color);
1042             }
1043         }
1044     },
1045 
1046     /**
1047      * @return {Number}
1048      */
1049     getSelectedIndex:function () {
1050         return this._selectedIndex;
1051     },
1052 
1053     /**
1054      * @param {Number} SelectedIndex
1055      */
1056     setSelectedIndex:function (SelectedIndex) {
1057         if (SelectedIndex != this._selectedIndex) {
1058             this._selectedIndex = SelectedIndex;
1059             var currItem = this.getChildByTag(cc.CURRENT_ITEM);
1060             if (currItem)
1061                 currItem.removeFromParent(false);
1062 
1063             var item = this._subItems[this._selectedIndex];
1064             this.addChild(item, 0, cc.CURRENT_ITEM);
1065             var s = item.getContentSize();
1066             this.setContentSize(s);
1067             item.setPosition(s.width / 2, s.height / 2);
1068         }
1069     },
1070 
1071     /**
1072      * similar to get children
1073      * @return {cc.MenuItem}
1074      */
1075     getSubItems:function () {
1076         return this._subItems;
1077     },
1078 
1079     /**
1080      * @param {cc.MenuItem} SubItems
1081      */
1082     setSubItems:function (SubItems) {
1083         this._subItems = SubItems;
1084     },
1085 
1086     /**
1087      * @param {cc.MenuItem} args[0...last-2] the rest in the array are cc.MenuItems
1088      * @param {function|String} args[last-1] the second item in the args array is the callback
1089      * @param {cc.Node} args[last] the first item in the args array is a target
1090      * @return {Boolean}
1091      */
1092     initWithItems:function (args) {
1093         var l =  args.length;
1094         // passing callback.
1095         if (typeof args[args.length-2] === 'function') {
1096             this.initWithCallback( args[args.length-2], args[args.length-1] );
1097             l = l-2;
1098         } else if(typeof args[args.length-1] === 'function'){
1099             this.initWithCallback( args[args.length-1], null );
1100             l = l-1;
1101         } else {
1102             this.initWithCallback(null, null);
1103         }
1104 
1105         this._subItems = [];
1106         for (var i = 0; i < l; i++) {
1107             if (args[i])
1108                 this._subItems.push(args[i]);
1109         }
1110         this._selectedIndex = cc.UINT_MAX;
1111         this.setSelectedIndex(0);
1112 
1113         this.setCascadeColorEnabled(true);
1114         this.setCascadeOpacityEnabled(true);
1115 
1116         return true;
1117     },
1118 
1119     /**
1120      * @param {cc.MenuItem} item
1121      */
1122     addSubItem:function (item) {
1123         this._subItems.push(item);
1124     },
1125 
1126     /**
1127      * activate the menu item
1128      */
1129     activate:function () {
1130         // update index
1131         if (this._isEnabled) {
1132             var newIndex = (this._selectedIndex + 1) % this._subItems.length;
1133             this.setSelectedIndex(newIndex);
1134         }
1135         cc.MenuItem.prototype.activate.call(this);
1136     },
1137 
1138     /**
1139      * menu item is selected (runs callback)
1140      */
1141     selected:function () {
1142         cc.MenuItem.prototype.selected.call(this);
1143         this._subItems[this._selectedIndex].selected();
1144     },
1145 
1146     /**
1147      * menu item goes back to unselected state
1148      */
1149     unselected:function () {
1150         cc.MenuItem.prototype.unselected.call(this);
1151         this._subItems[this._selectedIndex].unselected();
1152     },
1153 
1154     /**
1155      * @param {Boolean} enabled
1156      */
1157     setEnabled:function (enabled) {
1158         if (this._isEnabled != enabled) {
1159             cc.MenuItem.prototype.setEnabled.call(this, enabled);
1160             var locItems = this._subItems;
1161             if (locItems && locItems.length > 0) {
1162                 for (var it = 0; it < locItems.length; it++)
1163                     locItems[it].setEnabled(enabled);
1164             }
1165         }
1166     },
1167 
1168     /**
1169      * returns the selected item
1170      * @return {cc.MenuItem}
1171      */
1172     selectedItem:function () {
1173         return this._subItems[this._selectedIndex];
1174     },
1175 
1176     onEnter:function () {
1177         cc.Node.prototype.onEnter.call(this);
1178         this.setSelectedIndex(this._selectedIndex);
1179     }
1180 });
1181 
1182 /**
1183  * create a simple container class that "toggles" it's inner items<br/>
1184  * The inner items can be any MenuItem
1185  * @return {cc.MenuItemToggle}
1186  * @example
1187  * // Example
1188  *
1189  * //create a toggle item with 2 menu items (which you can then toggle between them later)
1190  * var toggler = cc.MenuItemToggle.create( cc.MenuItemFont.create("On"), cc.MenuItemFont.create("Off"), this.callback, this)
1191  * //Note: the first param is the target, the second is the callback function, afterwards, you can pass in any number of menuitems
1192  *
1193  * //if you pass only 1 variable, then it must be a cc.MenuItem
1194  * var notYetToggler = cc.MenuItemToggle.create(cc.MenuItemFont.create("On"));//it is useless right now, until you add more stuff to it
1195  * notYetToggler.addSubItem(cc.MenuItemFont.create("Off"));
1196  * //this is useful for constructing a toggler without a callback function (you wish to control the behavior from somewhere else)
1197  */
1198 cc.MenuItemToggle.create = function (/*Multiple arguments follow*/) {
1199     if((arguments.length > 0) && (arguments[arguments.length-1] == null))
1200         cc.log("parameters should not be ending with null in Javascript");
1201     var ret = new cc.MenuItemToggle();
1202     ret.initWithItems(arguments);
1203     return ret;
1204 };
1205