1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3 
  4  http://www.cocos2d-x.org
  5 
  6  Permission is hereby granted, free of charge, to any person obtaining a copy
  7  of this software and associated documentation files (the "Software"), to deal
  8  in the Software without restriction, including without limitation the rights
  9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  copies of the Software, and to permit persons to whom the Software is
 11  furnished to do so, subject to the following conditions:
 12 
 13  The above copyright notice and this permission notice shall be included in
 14  all copies or substantial portions of the Software.
 15 
 16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  THE SOFTWARE.
 23  ****************************************************************************/
 24 
 25 /**
 26  * slider event type
 27  * @type {Obejct}
 28  */
 29 ccs.SliderEventType = {percent_changed: 0};
 30 
 31 ccs.BASEBARRENDERERZ = -3;
 32 ccs.PROGRESSBARRENDERERZ = -2;
 33 ccs.SLIDBALLRENDERERZ = -1;
 34 /**
 35  * Base class for ccs.Slider
 36  * @class
 37  * @extends ccs.Widget
 38  */
 39 ccs.Slider = ccs.Widget.extend(/** @lends ccs.Slider# */{
 40     _barRenderer: null,
 41     _progressBarRenderer: null,
 42     _progressBarTextureSize: null,
 43     _slidBallNormalRenderer: null,
 44     _slidBallPressedRenderer: null,
 45     _slidBallDisabledRenderer: null,
 46     _slidBallRenderer: null,
 47     _barLength: 0,
 48     _percent: 0,
 49     _scale9Enabled: false,
 50     _prevIgnoreSize: true,
 51     _textureFile: "",
 52     _progressBarTextureFile: "",
 53     _slidBallNormalTextureFile: "",
 54     _slidBallPressedTextureFile: "",
 55     _slidBallDisabledTextureFile: "",
 56     _capInsetsBarRenderer: null,
 57     _capInsetsProgressBarRenderer: null,
 58     _sliderEventListener: null,
 59     _sliderEventSelector: null,
 60     _barTexType: null,
 61     _progressBarTexType: null,
 62     _ballNTexType: null,
 63     _ballPTexType: null,
 64     _ballDTexType: null,
 65     _isTextureLoaded: false,
 66     ctor: function () {
 67         ccs.Widget.prototype.ctor.call(this);
 68         this._barRenderer = null;
 69         this._progressBarRenderer = null;
 70         this._progressBarTextureSize = cc.size(0, 0);
 71         this._slidBallNormalRenderer = null;
 72         this._slidBallPressedRenderer = null;
 73         this._slidBallDisabledRenderer = null;
 74         this._slidBallRenderer = null;
 75         this._barLength = 0;
 76         this._percent = 0;
 77         this._scale9Enabled = false;
 78         this._prevIgnoreSize = true;
 79         this._textureFile = "";
 80         this._progressBarTextureFile = "";
 81         this._slidBallNormalTextureFile = "";
 82         this._slidBallPressedTextureFile = "";
 83         this._slidBallDisabledTextureFile = "";
 84         this._capInsetsBarRenderer = cc.RectZero();
 85         this._capInsetsProgressBarRenderer = cc.RectZero();
 86         this._sliderEventListener = null;
 87         this._sliderEventSelector = null;
 88         this._barTexType = ccs.TextureResType.local;
 89         this._progressBarTexType = ccs.TextureResType.local;
 90         this._ballNTexType = ccs.TextureResType.local;
 91         this._ballPTexType = ccs.TextureResType.local;
 92         this._ballDTexType = ccs.TextureResType.local;
 93         this._isTextureLoaded = false;
 94     },
 95 
 96     init:function(){
 97         if(ccs.Widget.prototype.init.call(this)){
 98             this.setTouchEnabled(true);
 99             return true;
100         }
101         return false;
102     },
103 
104     initRenderer: function () {
105         this._barRenderer = cc.Sprite.create();
106         this._progressBarRenderer = cc.Sprite.create();
107         this._progressBarRenderer.setAnchorPoint(0.0, 0.5);
108         cc.Node.prototype.addChild.call(this, this._barRenderer, ccs.BASEBARRENDERERZ, -1);
109         cc.Node.prototype.addChild.call(this, this._progressBarRenderer, ccs.PROGRESSBARRENDERERZ, -1);
110         this._slidBallNormalRenderer = cc.Sprite.create();
111         this._slidBallPressedRenderer = cc.Sprite.create();
112         this._slidBallPressedRenderer.setVisible(false);
113         this._slidBallDisabledRenderer = cc.Sprite.create();
114         this._slidBallDisabledRenderer.setVisible(false);
115         this._slidBallRenderer = cc.Node.create();
116         this._slidBallRenderer.addChild(this._slidBallNormalRenderer);
117         this._slidBallRenderer.addChild(this._slidBallPressedRenderer);
118         this._slidBallRenderer.addChild(this._slidBallDisabledRenderer);
119         cc.Node.prototype.addChild.call(this, this._slidBallRenderer, ccs.SLIDBALLRENDERERZ, -1);
120     },
121 
122     /**
123      * Load texture for slider bar.
124      * @param {String} fileName
125      * @param {ccs.TextureResType} texType
126      */
127     loadBarTexture: function (fileName, texType) {
128         if (!fileName) {
129             return;
130         }
131         texType = texType || ccs.TextureResType.local;
132         this._textureFile = fileName;
133         this._barTexType = texType;
134         var barRenderer = this._barRenderer;
135         switch (this._barTexType) {
136             case ccs.TextureResType.local:
137                 barRenderer.initWithFile(fileName);
138                 break;
139             case ccs.TextureResType.plist:
140                 barRenderer.initWithSpriteFrameName(fileName);
141                 break;
142             default:
143                 break;
144         }
145         this.updateRGBAToRenderer(barRenderer);
146         this.barRendererScaleChangedWithSize();
147 
148         if (!barRenderer.textureLoaded()) {
149             barRenderer.addLoadedEventListener(function () {
150                 this.barRendererScaleChangedWithSize();
151             }, this);
152         }
153     },
154 
155     /**
156      * Load dark state texture for slider progress bar.
157      * @param {String} fileName
158      * @param {ccs.TextureResType} texType
159      */
160     loadProgressBarTexture: function (fileName, texType) {
161         if (!fileName) {
162             return;
163         }
164         texType = texType || ccs.TextureResType.local;
165         this._progressBarTextureFile = fileName;
166         this._progressBarTexType = texType;
167         var progressBarRenderer = this._progressBarRenderer;
168         switch (this._progressBarTexType) {
169             case ccs.TextureResType.local:
170                 progressBarRenderer.initWithFile(fileName);
171                 break;
172             case ccs.TextureResType.plist:
173                 progressBarRenderer.initWithSpriteFrameName(fileName);
174                 break;
175             default:
176                 break;
177         }
178         this.updateRGBAToRenderer(progressBarRenderer);
179         progressBarRenderer.setAnchorPoint(0.0, 0.5);
180         var locSize = progressBarRenderer.getContentSize();
181         this._progressBarTextureSize.width = locSize.width;
182         this._progressBarTextureSize.height = locSize.height;
183         this.progressBarRendererScaleChangedWithSize();
184 
185         var textLoaded = progressBarRenderer.textureLoaded();
186         this._isTextureLoaded = textLoaded;
187         if (!textLoaded) {
188             progressBarRenderer.addLoadedEventListener(function () {
189                 this._isTextureLoaded = true;
190                 var locSize = progressBarRenderer.getContentSize();
191                 this._progressBarTextureSize.width = locSize.width;
192                 this._progressBarTextureSize.height = locSize.height;
193                 this.progressBarRendererScaleChangedWithSize();
194             }, this);
195         }
196     },
197 
198     /**
199      * Sets if slider is using scale9 renderer.
200      * @param {Boolean} able
201      */
202     setScale9Enabled: function (able) {
203         if (this._scale9Enabled == able) {
204             return;
205         }
206 
207         this._scale9Enabled = able;
208         cc.Node.prototype.removeChild.call(this, this._barRenderer, true);
209         cc.Node.prototype.removeChild.call(this, this._progressBarRenderer, true);
210         this._barRenderer = null;
211         this._progressBarRenderer = null;
212         if (this._scale9Enabled) {
213             this._barRenderer = cc.Scale9Sprite.create();
214             this._progressBarRenderer = cc.Scale9Sprite.create();
215         }
216         else {
217             this._barRenderer = cc.Sprite.create();
218             this._progressBarRenderer = cc.Sprite.create();
219         }
220         this.loadBarTexture(this._textureFile, this._barTexType);
221         this.loadProgressBarTexture(this._progressBarTextureFile, this._progressBarTexType);
222         cc.Node.prototype.addChild.call(this, this._barRenderer, ccs.BASEBARRENDERERZ, -1);
223         cc.Node.prototype.addChild.call(this, this._progressBarRenderer, ccs.PROGRESSBARRENDERERZ, -1);
224         if (this._scale9Enabled) {
225             var ignoreBefore = this._ignoreSize;
226             this.ignoreContentAdaptWithSize(false);
227             this._prevIgnoreSize = ignoreBefore;
228         }
229         else {
230             this.ignoreContentAdaptWithSize(this._prevIgnoreSize);
231         }
232         this.setCapInsetsBarRenderer(this._capInsetsBarRenderer);
233         this.setCapInsetProgressBarRebderer(this._capInsetsProgressBarRenderer);
234     },
235 
236     /**
237      * Get  slider is using scale9 renderer or not.
238      * @returns {Boolean}
239      */
240     isScale9Enabled:function(){
241         return this._scale9Enabled;
242     },
243 
244     /**
245      * override "ignoreContentAdaptWithSize" method of widget.
246      * @param {Boolean} ignore
247      */
248     ignoreContentAdaptWithSize: function (ignore) {
249         if (!this._scale9Enabled || (this._scale9Enabled && !ignore)) {
250             ccs.Widget.prototype.ignoreContentAdaptWithSize.call(this, ignore);
251             this._prevIgnoreSize = ignore;
252         }
253     },
254 
255     /**
256      * Sets capinsets for slider, if slider is using scale9 renderer.
257      * @param {cc.Rect} capInsets
258      */
259     setCapInsets: function (capInsets) {
260         this.setCapInsetsBarRenderer(capInsets);
261         this.setCapInsetProgressBarRebderer(capInsets);
262     },
263 
264     /**
265      * Sets capinsets for slider, if slider is using scale9 renderer.
266      * @param {cc.Rect} capInsets
267      */
268     setCapInsetsBarRenderer: function (capInsets) {
269         this._capInsetsBarRenderer = capInsets;
270         if (!this._scale9Enabled) {
271             return;
272         }
273         this._barRenderer.setCapInsets(capInsets);
274     },
275 
276     /**
277      * Get cap insets for slider.
278      * @returns {cc.Rect}
279      */
280     getCapInsetBarRenderer:function(){
281         return this._capInsetsBarRenderer;
282     },
283 
284     /**
285      * Sets capinsets for slider, if slider is using scale9 renderer.
286      * @param {cc.Rect} capInsets
287      */
288     setCapInsetProgressBarRebderer: function (capInsets) {
289         this._capInsetsProgressBarRenderer = capInsets;
290         if (!this._scale9Enabled) {
291             return;
292         }
293         this._progressBarRenderer.setCapInsets(capInsets);
294     },
295 
296     /**
297      * Get cap insets for slider.
298      * @returns {cc.Rect}
299      */
300     getCapInsetProgressBarRebderer:function(){
301         return this._capInsetsProgressBarRenderer;
302     },
303 
304     /**
305      * Load textures for slider ball.
306      * @param {String} normal
307      * @param {String} pressed
308      * @param {String} disabled
309      * @param {ccs.TextureResType} texType
310      */
311     loadSlidBallTextures: function (normal, pressed, disabled, texType) {
312         this.loadSlidBallTextureNormal(normal, texType);
313         this.loadSlidBallTexturePressed(pressed, texType);
314         this.loadSlidBallTextureDisabled(disabled, texType);
315     },
316 
317     /**
318      * Load normal state texture for slider ball.
319      * @param {String} normal
320      * @param {ccs.TextureResType} texType
321      */
322     loadSlidBallTextureNormal: function (normal, texType) {
323         if (!normal) {
324             return;
325         }
326         texType = texType || ccs.TextureResType.local;
327         this._slidBallNormalTextureFile = normal;
328         this._ballNTexType = texType;
329         switch (this._ballNTexType) {
330             case ccs.TextureResType.local:
331                 this._slidBallNormalRenderer.initWithFile(normal);
332                 break;
333             case ccs.TextureResType.plist:
334                 this._slidBallNormalRenderer.initWithSpriteFrameName(normal);
335                 break;
336             default:
337                 break;
338         }
339         this.updateRGBAToRenderer(this._slidBallNormalRenderer);
340     },
341 
342     /**
343      * Load selected state texture for slider ball.
344      * @param {String} pressed
345      * @param {ccs.TextureResType} texType
346      */
347     loadSlidBallTexturePressed: function (pressed, texType) {
348         if (!pressed) {
349             return;
350         }
351         texType = texType || ccs.TextureResType.local;
352         this._slidBallPressedTextureFile = pressed;
353         this._ballPTexType = texType;
354         switch (this._ballPTexType) {
355             case ccs.TextureResType.local:
356                 this._slidBallPressedRenderer.initWithFile(pressed);
357                 break;
358             case ccs.TextureResType.plist:
359                 this._slidBallPressedRenderer.initWithSpriteFrameName(pressed);
360                 break;
361             default:
362                 break;
363         }
364         this.updateRGBAToRenderer(this._slidBallPressedRenderer);
365     },
366 
367     /**
368      * Load dark state texture for slider ball.
369      * @param {String} disabled
370      * @param {ccs.TextureResType} texType
371      */
372     loadSlidBallTextureDisabled: function (disabled, texType) {
373         if (!disabled) {
374             return;
375         }
376         texType = texType || ccs.TextureResType.local;
377         this._slidBallDisabledTextureFile = disabled;
378         this._ballDTexType = texType;
379         switch (this._ballDTexType) {
380             case ccs.TextureResType.local:
381                 this._slidBallDisabledRenderer.initWithFile(disabled);
382                 break;
383             case ccs.TextureResType.plist:
384                 this._slidBallDisabledRenderer.initWithSpriteFrameName(disabled);
385                 break;
386             default:
387                 break;
388         }
389         this.updateRGBAToRenderer(this._slidBallDisabledRenderer);
390     },
391 
392     /**
393      * Changes the progress direction of slider.
394      * @param {number} percent
395      */
396     setPercent: function (percent) {
397         if (percent > 100) {
398             percent = 100;
399         }
400         if (percent < 0) {
401             percent = 0;
402         }
403         this._percent = percent;
404         if(!this._isTextureLoaded){
405             return;
406         }
407         var dis = this._barLength * (percent / 100.0);
408         this._slidBallRenderer.setPosition(cc.p(-this._barLength / 2.0 + dis, 0.0));
409         if (this._scale9Enabled) {
410             this._progressBarRenderer.setPreferredSize(cc.size(dis, this._progressBarTextureSize.height));
411         }
412         else {
413             var x = 0, y = 0;
414             if (this._progressBarTexType == ccs.TextureResType.plist) {
415                 var barNode = this._progressBarRenderer;
416                 if (barNode) {
417                     var to = barNode.getTextureRect()._origin;
418                     x = to.x;
419                     y = to.y;
420                 }
421             }
422             this._progressBarRenderer.setTextureRect(cc.rect(x, y, this._progressBarTextureSize.width * (percent / 100.0), this._progressBarTextureSize.height));
423         }
424     },
425 
426     onTouchBegan: function (touch , event) {
427         var pass = ccs.Widget.prototype.onTouchBegan.call(this,touch , event);
428         if(this._hitted){
429             var nsp = this.convertToNodeSpace(this._touchStartPos);
430             this.setPercent(this.getPercentWithBallPos(nsp.x));
431             this.percentChangedEvent();
432         }
433         return pass;
434     },
435 
436     onTouchMoved: function (touch , event) {
437         var touchPoint = touch.getLocation();
438         this._touchMovePos.x = touchPoint.x;
439         this._touchMovePos.y = touchPoint.y;
440         var nsp = this.convertToNodeSpace(touchPoint);
441         this._slidBallRenderer.setPosition(cc.p(nsp.x, 0));
442         this.setPercent(this.getPercentWithBallPos(nsp.x));
443         this.percentChangedEvent();
444     },
445 
446     onTouchEnded: function (touch , event) {
447         ccs.Widget.prototype.onTouchEnded.call(this, touch , event);
448     },
449 
450     onTouchCancelled: function (touch , event) {
451         ccs.Widget.prototype.onTouchCancelled.call(this, touch , event);
452     },
453 
454     /**
455      * get percent with ballPos
456      * @param {cc.Point} px
457      * @returns {number}
458      */
459     getPercentWithBallPos: function (px) {
460         return (((px - (-this._barLength / 2.0)) / this._barLength) * 100.0);
461     },
462 
463     /**
464      * add event listener
465      * @param {Function} selector
466      * @param {Object} target
467      */
468     addEventListenerSlider: function (selector, target) {
469         this._sliderEventSelector = selector;
470         this._sliderEventListener = target;
471     },
472 
473     percentChangedEvent: function () {
474         if (this._sliderEventListener && this._sliderEventSelector) {
475             this._sliderEventSelector.call(this._sliderEventListener, this, ccs.SliderEventType.percent_changed);
476         }
477     },
478 
479     /**
480      * Gets the progress direction of slider.
481      * @returns {number}
482      */
483     getPercent: function () {
484         return this._percent;
485     },
486 
487     onSizeChanged: function () {
488         ccs.Widget.prototype.onSizeChanged.call(this);
489         this.barRendererScaleChangedWithSize();
490         this.progressBarRendererScaleChangedWithSize();
491     },
492 
493     /**
494      * override "getContentSize" method of widget.
495      * @returns {cc.Size}
496      */
497     getContentSize: function () {
498         var locContentSize = this._barRenderer.getContentSize();
499         return cc.size(locContentSize.width,locContentSize.height);
500     },
501 
502     /**
503      * override "getContentSize" method of widget.
504      * @returns {cc.Node}
505      */
506     getVirtualRenderer: function () {
507         return this._barRenderer;
508     },
509 
510     barRendererScaleChangedWithSize: function () {
511         if (this._ignoreSize) {
512             this._barRenderer.setScale(1.0);
513             var locSize = this._barRenderer.getContentSize();
514             this._size.width = locSize.width;
515             this._size.height = locSize.height;
516             this._barLength = locSize.width;
517         }
518         else {
519             this._barLength = this._size.width;
520             if (this._scale9Enabled) {
521                 this._barRenderer.setPreferredSize(cc.size(this._size.width,this._size.height));
522             }
523             else {
524                 var btextureSize = this._barRenderer.getContentSize();
525                 if (btextureSize.width <= 0.0 || btextureSize.height <= 0.0) {
526                     this._barRenderer.setScale(1.0);
527                     return;
528                 }
529                 var bscaleX = this._size.width / btextureSize.width;
530                 var bscaleY = this._size.height / btextureSize.height;
531                 this._barRenderer.setScaleX(bscaleX);
532                 this._barRenderer.setScaleY(bscaleY);
533             }
534         }
535         this.setPercent(this._percent);
536     },
537 
538     progressBarRendererScaleChangedWithSize: function () {
539         if (this._ignoreSize) {
540             if (!this._scale9Enabled) {
541                 var ptextureSize = this._progressBarTextureSize;
542                 var pscaleX = this._size.width / ptextureSize.width;
543                 var pscaleY = this._size.height / ptextureSize.height;
544                 this._progressBarRenderer.setScaleX(pscaleX);
545                 this._progressBarRenderer.setScaleY(pscaleY);
546             }
547         }
548         else {
549             if (this._scale9Enabled) {
550                 this._progressBarRenderer.setPreferredSize(cc.size(this._size.width,this._size.height));
551             }
552             else {
553                 var ptextureSize = this._progressBarTextureSize;
554                 if (ptextureSize.width <= 0.0 || ptextureSize.height <= 0.0) {
555                     this._progressBarRenderer.setScale(1.0);
556                     return;
557                 }
558                 var pscaleX = this._size.width / ptextureSize.width;
559                 var pscaleY = this._size.height / ptextureSize.height;
560                 this._progressBarRenderer.setScaleX(pscaleX);
561                 this._progressBarRenderer.setScaleY(pscaleY);
562             }
563         }
564         this._progressBarRenderer.setPosition(cc.p(-this._barLength * 0.5, 0.0));
565         this.setPercent(this._percent);
566     },
567 
568     onPressStateChangedToNormal: function () {
569         this._slidBallNormalRenderer.setVisible(true);
570         this._slidBallPressedRenderer.setVisible(false);
571         this._slidBallDisabledRenderer.setVisible(false);
572     },
573 
574     onPressStateChangedToPressed: function () {
575         this._slidBallNormalRenderer.setVisible(false);
576         this._slidBallPressedRenderer.setVisible(true);
577         this._slidBallDisabledRenderer.setVisible(false);
578     },
579 
580     onPressStateChangedToDisabled: function () {
581         this._slidBallNormalRenderer.setVisible(false);
582         this._slidBallPressedRenderer.setVisible(false);
583         this._slidBallDisabledRenderer.setVisible(true);
584     },
585 
586     updateTextureColor: function () {
587         this.updateColorToRenderer(this._barRenderer);
588         this.updateColorToRenderer(this._progressBarRenderer);
589         this.updateColorToRenderer(this._slidBallNormalRenderer);
590         this.updateColorToRenderer(this._slidBallPressedRenderer);
591         this.updateColorToRenderer(this._slidBallDisabledRenderer);
592     },
593 
594     updateTextureOpacity: function () {
595         this.updateOpacityToRenderer(this._barRenderer);
596         this.updateOpacityToRenderer(this._progressBarRenderer);
597         this.updateOpacityToRenderer(this._slidBallNormalRenderer);
598         this.updateOpacityToRenderer(this._slidBallPressedRenderer);
599         this.updateOpacityToRenderer(this._slidBallDisabledRenderer);
600     },
601 
602     updateTextureRGBA: function () {
603         this.updateRGBAToRenderer(this._barRenderer);
604         this.updateRGBAToRenderer(this._progressBarRenderer);
605         this.updateRGBAToRenderer(this._slidBallNormalRenderer);
606         this.updateRGBAToRenderer(this._slidBallPressedRenderer);
607         this.updateRGBAToRenderer(this._slidBallDisabledRenderer);
608     },
609 
610     /**
611      * Returns the "class name" of widget.
612      * @returns {string}
613      */
614     getDescription: function () {
615         return "Slider";
616     },
617 
618     createCloneInstance: function () {
619         return ccs.Slider.create();
620     },
621 
622     copySpecialProperties: function (slider) {
623         this._prevIgnoreSize = slider._prevIgnoreSize;
624         this.setScale9Enabled(slider._scale9Enabled);
625         this.loadBarTexture(slider._textureFile, slider._barTexType);
626         this.loadProgressBarTexture(slider._progressBarTextureFile, slider._progressBarTexType);
627         this.loadSlidBallTextureNormal(slider._slidBallNormalTextureFile, slider._ballNTexType);
628         this.loadSlidBallTexturePressed(slider._slidBallPressedTextureFile, slider._ballPTexType);
629         this.loadSlidBallTextureDisabled(slider._slidBallDisabledTextureFile, slider._ballDTexType);
630         this.setPercent(slider.getPercent());
631     }
632 });
633 /**
634  * allocates and initializes a UISlider.
635  * @constructs
636  * @return {ccs.Slider}
637  * @example
638  * // example
639  * var uiSlider = ccs.Slider.create();
640  */
641 ccs.Slider.create = function () {
642     var uiSlider = new ccs.Slider();
643     if (uiSlider && uiSlider.init()) {
644         return uiSlider;
645     }
646     return null;
647 };