1 /**
  2  *
  3  * Copyright (c) 2008-2010 Ricardo Quesada
  4  * Copyright (c) 2011-2012 cocos2d-x.org
  5  * Copyright (c) 2013-2014 Chukong Technologies Inc.
  6  *
  7  * Copyright 2011 Yannick Loriot. All rights reserved.
  8  * http://yannickloriot.com
  9  *
 10  * Permission is hereby granted, free of charge, to any person obtaining a copy
 11  * of this software and associated documentation files (the "Software"), to deal
 12  * in the Software without restriction, including without limitation the rights
 13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 14  * copies of the Software, and to permit persons to whom the Software is
 15  * furnished to do so, subject to the following conditions:
 16  *
 17  * The above copyright notice and this permission notice shall be included in
 18  * all copies or substantial portions of the Software.
 19  *
 20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 26  * THE SOFTWARE.
 27  *
 28  *
 29  * converted to Javascript / cocos2d-x by Angus C
 30  */
 31 
 32 /**
 33  * @ignore
 34  */
 35 cc.SLIDER_MARGIN_H = 24;
 36 cc.SLIDER_MARGIN_V = 8;
 37 
 38 /**
 39  * ControlSlider: Slider ui component.
 40  * @class
 41  * @extends cc.Control
 42  *
 43  * @property {Number}       value               - The value of the slider
 44  * @property {Number}       minValue            - The minimum value of the slider
 45  * @property {Number}       maxValue            - The maximum value of the slider
 46  * @property {Number}       minAllowedValue     - The minimum allowed value of the slider
 47  * @property {Number}       maxAllowedValue     - The maximum allowed value of the slider
 48  * @property {Number}       thumbSprite         - <@readonly> Brightness value of the picker
 49  * @property {cc.Sprite}    progressSprite      - <@readonly> The background sprite
 50  * @property {cc.Sprite}    backgroundSprite    - <@readonly> The overlay sprite
 51  */
 52 cc.ControlSlider = cc.Control.extend(/** @lends cc.ControlSlider# */{
 53     _value:0,
 54     _minimumValue:0,
 55     _maximumValue:0,
 56     _minimumAllowedValue:0,
 57     _maximumAllowedValue:0,
 58 
 59     _thumbSprite:null,
 60     _progressSprite:null,
 61     _backgroundSprite:null,
 62     _className:"ControlSlider",
 63 
 64     ctor:function (bgFile, progressFile, thumbFile) {
 65         cc.Control.prototype.ctor.call(this);
 66         if (thumbFile != undefined) {
 67             // Prepare background for slider
 68             bgSprite = cc.Sprite.create(bgFile);
 69 
 70             // Prepare progress for slider
 71             progressSprite = cc.Sprite.create(progressFile);
 72 
 73             // Prepare thumb (menuItem) for slider
 74             thumbSprite = cc.Sprite.create(thumbFile);
 75 
 76             this.initWithSprites(bgSprite, progressSprite, thumbSprite);
 77         }
 78     },
 79 
 80     getValue:function () {
 81         return this._value;
 82     },
 83     setValue:function (value) {
 84         //clamp between the two bounds
 85         value = Math.max(value, this._minimumValue);
 86         value = Math.min(value, this._maximumValue);
 87         this._value = value;
 88         this.needsLayout();
 89         this.sendActionsForControlEvents(cc.CONTROL_EVENT_VALUECHANGED);
 90     },
 91 
 92     getMinimumValue:function () {
 93         return this._minimumValue;
 94     },
 95     setMinimumValue:function (minimumValue) {
 96         this._minimumValue = minimumValue;
 97         this._minimumAllowedValue = minimumValue;
 98         if (this._minimumValue >= this._maximumValue)
 99             this._maximumValue = this._minimumValue + 1.0;
100         this.setValue(this._value);
101     },
102 
103     getMaximumValue:function () {
104         return this._maximumValue;
105     },
106     setMaximumValue:function (maximumValue) {
107         this._maximumValue = maximumValue;
108         this._maximumAllowedValue = maximumValue;
109         if (this._maximumValue <= this._minimumValue)
110             this._minimumValue = this._maximumValue - 1.0;
111         this.setValue(this._value);
112     },
113     isTouchInside:function (touch) {
114         var touchLocation = touch.getLocation();
115         touchLocation = this.getParent().convertToNodeSpace(touchLocation);
116 
117         var rect = this.getBoundingBox();
118         rect.width += this._thumbSprite.getContentSize().width;
119         rect.x -= this._thumbSprite.getContentSize().width / 2;
120 
121         return cc.rectContainsPoint(rect, touchLocation);
122     },
123     locationFromTouch:function (touch) {
124         var touchLocation = touch.getLocation();                      // Get the touch position
125         touchLocation = this.convertToNodeSpace(touchLocation);                  // Convert to the node space of this class
126 
127         if (touchLocation.x < 0) {
128             touchLocation.x = 0;
129         } else if (touchLocation.x > this._backgroundSprite.getContentSize().width) {
130             touchLocation.x = this._backgroundSprite.getContentSize().width;
131         }
132 
133         return touchLocation;
134     },
135     getMinimumAllowedValue:function () {
136         return this._minimumAllowedValue;
137     },
138     setMinimumAllowedValue:function (val) {
139         this._minimumAllowedValue = val;
140     },
141 
142     getMaximumAllowedValue:function () {
143         return this._maximumAllowedValue;
144     },
145 
146     setMaximumAllowedValue:function (val) {
147         this._maximumAllowedValue = val;
148     },
149 
150     getThumbSprite:function () {
151         return this._thumbSprite;
152     },
153     getProgressSprite:function () {
154         return this._progressSprite;
155     },
156     getBackgroundSprite:function () {
157         return this._backgroundSprite;
158     },
159 
160     /**
161      * Initializes a slider with a background sprite, a progress bar and a thumb
162      * item.
163      *
164      * @param {cc.Sprite} backgroundSprite  CCSprite, that is used as a background.
165      * @param {cc.Sprite} progressSprite    CCSprite, that is used as a progress bar.
166      * @param {cc.Sprite} thumbSprite         CCMenuItem, that is used as a thumb.
167      */
168     initWithSprites:function (backgroundSprite, progressSprite, thumbSprite) {
169         if (cc.Control.prototype.init.call(this)) {
170             this.ignoreAnchorPointForPosition(false);
171 
172             this._backgroundSprite = backgroundSprite;
173             this._progressSprite = progressSprite;
174             this._thumbSprite = thumbSprite;
175 
176             // Defines the content size
177             var maxRect = cc.ControlUtils.CCRectUnion(backgroundSprite.getBoundingBox(), thumbSprite.getBoundingBox());
178             this.setContentSize(maxRect.width, maxRect.height);
179 
180             // Add the slider background
181             this._backgroundSprite.setAnchorPoint(0.5, 0.5);
182             this._backgroundSprite.setPosition(maxRect.width / 2, maxRect.height / 2);
183             this.addChild(this._backgroundSprite);
184 
185             // Add the progress bar
186             this._progressSprite.setAnchorPoint(0.0, 0.5);
187             this._progressSprite.setPosition(0, maxRect.height / 2);
188             this.addChild(this._progressSprite);
189 
190             // Add the slider thumb
191             this._thumbSprite.setPosition(0, maxRect.height / 2);
192             this.addChild(this._thumbSprite);
193 
194             // Init default values
195             this._minimumValue = 0.0;
196             this._maximumValue = 1.0;
197             this.setValue(this._minimumValue);
198             return true;
199         } else
200             return false;
201     },
202 
203     setEnabled:function (enabled) {
204         cc.Control.prototype.setEnabled.call(this, enabled);
205         if (this._thumbSprite) {
206             this._thumbSprite.setOpacity(enabled ? 255 : 128);
207         }
208     },
209 
210     sliderBegan:function (location) {
211         this.setSelected(true);
212         this.getThumbSprite().setColor(cc.color.GRAY);
213         this.setValue(this.valueForLocation(location));
214     },
215     sliderMoved:function (location) {
216         this.setValue(this.valueForLocation(location));
217     },
218     sliderEnded:function (location) {
219         if (this.isSelected()) {
220             this.setValue(this.valueForLocation(this._thumbSprite.getPosition()));
221         }
222         this._thumbSprite.setColor(cc.color.WHITE);
223         this.setSelected(false);
224     },
225 
226     getTouchLocationInControl:function (touch) {
227         var touchLocation = touch.getLocation();                      // Get the touch position
228         touchLocation = this.convertToNodeSpace(touchLocation);         // Convert to the node space of this class
229 
230         if (touchLocation.x < 0) {
231             touchLocation.x = 0;
232         } else if (touchLocation.x > this._backgroundSprite.getContentSize().width + cc.SLIDER_MARGIN_H) {
233             touchLocation.x = this._backgroundSprite.getContentSize().width + cc.SLIDER_MARGIN_H;
234         }
235         return touchLocation;
236     },
237 
238     onTouchBegan:function (touch, event) {
239         if (!this.isTouchInside(touch)|| !this.isEnabled() || !this.isVisible())
240             return false;
241 
242         var location = this.locationFromTouch(touch);
243         this.sliderBegan(location);
244         return true;
245     },
246     onTouchMoved:function (touch, event) {
247         var location = this.locationFromTouch(touch);
248         this.sliderMoved(location);
249     },
250     onTouchEnded:function (touch, event) {
251         this.sliderEnded(cc.p(0,0));
252     },
253     needsLayout:function(){
254         var percent = (this._value - this._minimumValue) / (this._maximumValue - this._minimumValue);
255         this._thumbSprite.setPositionX(percent * this._backgroundSprite.getContentSize().width);
256 
257         // Stretches content proportional to newLevel
258         var textureRect = this._progressSprite.getTextureRect();
259         textureRect = cc.rect(textureRect.x, textureRect.y, this._thumbSprite.getPositionX(), textureRect.height);
260         this._progressSprite.setTextureRect(textureRect, this._progressSprite.isTextureRectRotated());
261     },
262     /** Returns the value for the given location. */
263     valueForLocation:function (location) {
264         var percent = location.x / this._backgroundSprite.getContentSize().width;
265         return Math.max(Math.min(this._minimumValue + percent * (this._maximumValue - this._minimumValue), this._maximumAllowedValue), this._minimumAllowedValue);
266     }
267 });
268 
269 var _p = cc.ControlSlider.prototype;
270 
271 // Extended properties
272 /** @expose */
273 _p.value;
274 cc.defineGetterSetter(_p, "value", _p.getValue, _p.setValue);
275 /** @expose */
276 _p.minValue;
277 cc.defineGetterSetter(_p, "minValue", _p.getMinimumValue, _p.setMinimumValue);
278 /** @expose */
279 _p.maxValue;
280 cc.defineGetterSetter(_p, "maxValue", _p.getMaximumValue, _p.setMaximumValue);
281 /** @expose */
282 _p.minAllowedValue;
283 cc.defineGetterSetter(_p, "minAllowedValue", _p.getMinimumAllowedValue, _p.setMinimumAllowedValue);
284 /** @expose */
285 _p.maxAllowedValue;
286 cc.defineGetterSetter(_p, "maxAllowedValue", _p.getMaximumAllowedValue, _p.setMaximumAllowedValue);
287 /** @expose */
288 _p.thumbSprite;
289 cc.defineGetterSetter(_p, "thumbSprite", _p.getThumbSprite);
290 /** @expose */
291 _p.progressSprite;
292 cc.defineGetterSetter(_p, "progressSprite", _p.getProgressSprite);
293 /** @expose */
294 _p.backgroundSprite;
295 cc.defineGetterSetter(_p, "backgroundSprite", _p.getBackgroundSprite);
296 
297 _p = null;
298 
299 /**
300  * Creates a slider with a given background sprite and a progress bar and a
301  * thumb item.
302  * @deprecated
303  * @see initWithBackgroundSprite:progressSprite:thumbMenuItem:
304  */
305 cc.ControlSlider.create = function (bgFile, progressFile, thumbFile) {
306     return new cc.ControlSlider(bgFile, progressFile, thumbFile);
307 };