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