1 /**
  2  *
  3  * Copyright (c) 2010-2012 cocos2d-x.org
  4  *
  5  * Copyright 2011 Yannick Loriot. All rights reserved.
  6  * http://yannickloriot.com
  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  * converted to Javascript / cocos2d-x by Angus C
 28  */
 29 
 30 cc.SLIDER_MARGIN_H = 24;
 31 cc.SLIDER_MARGIN_V = 8;
 32 
 33 cc.ControlSlider = cc.Control.extend({
 34     _value:0,
 35     _minimumValue:0,
 36     _maximumValue:0,
 37     _minimumAllowedValue:0,
 38     _maximumAllowedValue:0,
 39 
 40     _thumbSprite:null,
 41     _progressSprite:null,
 42     _backgroundSprite:null,
 43 
 44     getValue:function () {
 45         return this._value;
 46     },
 47     setValue:function (value) {
 48         //clamp between the two bounds
 49         value = Math.max(value, this._minimumValue);
 50         value = Math.min(value, this._maximumValue);
 51         this._value = value;
 52         this.needsLayout();
 53         this.sendActionsForControlEvents(cc.CONTROL_EVENT_VALUECHANGED);
 54     },
 55 
 56     getMinimumValue:function () {
 57         return this._minimumValue;
 58     },
 59     setMinimumValue:function (minimumValue) {
 60         this._minimumValue = minimumValue;
 61         this._minimumAllowedValue = minimumValue;
 62         if (this._minimumValue >= this._maximumValue)
 63             this._maximumValue = this._minimumValue + 1.0;
 64         this.setValue(this._value);
 65     },
 66 
 67     getMaximumValue:function () {
 68         return this._maximumValue;
 69     },
 70     setMaximumValue:function (maximumValue) {
 71         this._maximumValue = maximumValue;
 72         this._maximumAllowedValue = maximumValue;
 73         if (this._maximumValue <= this._minimumValue)
 74             this._minimumValue = this._maximumValue - 1.0;
 75         this.setValue(this._value);
 76     },
 77     isTouchInside:function (touch) {
 78         var touchLocation = touch.getLocation();
 79         touchLocation = this.getParent().convertToNodeSpace(touchLocation);
 80 
 81         var rect = this.getBoundingBox();
 82         rect._size.width += this._thumbSprite.getContentSize().width;
 83         rect._origin.x -= this._thumbSprite.getContentSize().width / 2;
 84 
 85         return cc.rectContainsPoint(rect, touchLocation);
 86     },
 87     locationFromTouch:function (touch) {
 88         var touchLocation = touch.getLocation();                      // Get the touch position
 89         touchLocation = this.convertToNodeSpace(touchLocation);                  // Convert to the node space of this class
 90 
 91         if (touchLocation.x < 0) {
 92             touchLocation.x = 0;
 93         } else if (touchLocation.x > this._backgroundSprite.getContentSize().width) {
 94             touchLocation.x = this._backgroundSprite.getContentSize().width;
 95         }
 96 
 97         return touchLocation;
 98     },
 99     getMinimumAllowedValue:function () {
100         return this._minimumAllowedValue;
101     },
102     setMinimumAllowedValue:function (val) {
103         this._minimumAllowedValue = val;
104     },
105 
106     getMaximumAllowedValue:function () {
107         return this._maximumAllowedValue;
108     },
109 
110     setMaximumAllowedValue:function (val) {
111         this._maximumAllowedValue = val;
112     },
113 
114     getThumbSprite:function () {
115         return this._thumbSprite;
116     },
117     getProgressSprite:function () {
118         return this._progressSprite;
119     },
120     getBackgroundSprite:function () {
121         return this._backgroundSprite;
122     },
123 
124     /**
125      * Initializes a slider with a background sprite, a progress bar and a thumb
126      * item.
127      *
128      * @param {cc.Sprite} backgroundSprite  CCSprite, that is used as a background.
129      * @param {cc.Sprite} progressSprite    CCSprite, that is used as a progress bar.
130      * @param {cc.Sprite} thumbSprite         CCMenuItem, that is used as a thumb.
131      */
132     initWithSprites:function (backgroundSprite, progressSprite, thumbSprite) {
133         if (cc.Control.prototype.init.call(this)) {
134             this.ignoreAnchorPointForPosition(false);
135             this.setTouchEnabled(true);
136 
137             this._backgroundSprite = backgroundSprite;
138             this._progressSprite = progressSprite;
139             this._thumbSprite = thumbSprite;
140 
141             // Defines the content size
142             var maxRect = cc.ControlUtils.CCRectUnion(backgroundSprite.getBoundingBox(), thumbSprite.getBoundingBox());
143             this.setContentSize(maxRect.width, maxRect.height);
144 
145             // Add the slider background
146             this._backgroundSprite.setAnchorPoint(0.5, 0.5);
147             this._backgroundSprite.setPosition(maxRect.width / 2, maxRect.height / 2);
148             this.addChild(this._backgroundSprite);
149 
150             // Add the progress bar
151             this._progressSprite.setAnchorPoint(0.0, 0.5);
152             this._progressSprite.setPosition(0, maxRect.height / 2);
153             this.addChild(this._progressSprite);
154 
155             // Add the slider thumb
156             this._thumbSprite.setPosition(0, maxRect.height / 2);
157             this.addChild(this._thumbSprite);
158 
159             // Init default values
160             this._minimumValue = 0.0;
161             this._maximumValue = 1.0;
162             this.setValue(this._minimumValue);
163             return true;
164         } else
165             return false;
166     },
167 
168     setEnabled:function (enabled) {
169         cc.Control.prototype.setEnabled.call(this, enabled);
170         if (this._thumbSprite) {
171             this._thumbSprite.setOpacity(enabled ? 255 : 128);
172         }
173     },
174 
175     sliderBegan:function (location) {
176         this.setSelected(true);
177         this.getThumbSprite().setColor(cc.gray());
178         this.setValue(this.valueForLocation(location));
179     },
180     sliderMoved:function (location) {
181         this.setValue(this.valueForLocation(location));
182     },
183     sliderEnded:function (location) {
184         if (this.isSelected()) {
185             this.setValue(this.valueForLocation(this._thumbSprite.getPosition()));
186         }
187         this._thumbSprite.setColor(cc.white());
188         this.setSelected(false);
189     },
190 
191     getTouchLocationInControl:function (touch) {
192         var touchLocation = touch.getLocation();                      // Get the touch position
193         touchLocation = this.convertToNodeSpace(touchLocation);         // Convert to the node space of this class
194 
195         if (touchLocation.x < 0) {
196             touchLocation.x = 0;
197         } else if (touchLocation.x > this._backgroundSprite.getContentSize().width + cc.SLIDER_MARGIN_H) {
198             touchLocation.x = this._backgroundSprite.getContentSize().width + cc.SLIDER_MARGIN_H;
199         }
200         return touchLocation;
201     },
202 
203     onTouchBegan:function (touch, event) {
204         if (!this.isTouchInside(touch)|| !this.isEnabled() || !this.isVisible())
205             return false;
206 
207         var location = this.locationFromTouch(touch);
208         this.sliderBegan(location);
209         return true;
210     },
211     onTouchMoved:function (touch, event) {
212         var location = this.locationFromTouch(touch);
213         this.sliderMoved(location);
214     },
215     onTouchEnded:function (touch, event) {
216         this.sliderEnded(cc.PointZero());
217     },
218     needsLayout:function(){
219         var percent = (this._value - this._minimumValue) / (this._maximumValue - this._minimumValue);
220         this._thumbSprite.setPositionX(percent * this._backgroundSprite.getContentSize().width);
221 
222         // Stretches content proportional to newLevel
223         var textureRect = this._progressSprite.getTextureRect();
224         textureRect = cc.rect(textureRect.x, textureRect.y, this._thumbSprite.getPositionX(), textureRect.height);
225         this._progressSprite.setTextureRect(textureRect, this._progressSprite.isTextureRectRotated(), textureRect._size);
226     },
227     /** Returns the value for the given location. */
228     valueForLocation:function (location) {
229         var percent = location.x / this._backgroundSprite.getContentSize().width;
230         return Math.max(Math.min(this._minimumValue + percent * (this._maximumValue - this._minimumValue), this._maximumAllowedValue), this._minimumAllowedValue);
231     }
232 });
233 
234 
235 /**
236  * Creates a slider with a given background sprite and a progress bar and a
237  * thumb item.
238  *
239  * @see initWithBackgroundSprite:progressSprite:thumbMenuItem:
240  */
241 cc.ControlSlider.create = function (bgFile, progressFile, thumbFile) {
242     if (typeof(bgFile) == "string") {
243         // Prepare background for slider
244         bgFile = cc.Sprite.create(bgFile);
245 
246         // Prepare progress for slider
247         progressFile = cc.Sprite.create(progressFile);
248 
249         // Prepare thumb (menuItem) for slider
250         thumbFile = cc.Sprite.create(thumbFile);
251     }
252 
253     var pRet = new cc.ControlSlider();
254     pRet.initWithSprites(bgFile, progressFile, thumbFile);
255     return pRet;
256 
257 };