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