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  * Copyright 2012 Yannick Loriot. All rights reserved.
  9  * http://yannickloriot.com
 10  * 
 11  * Permission is hereby granted, free of charge, to any person obtaining a copy
 12  * of this software and associated documentation files (the "Software"), to deal
 13  * in the Software without restriction, including without limitation the rights
 14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 15  * copies of the Software, and to permit persons to whom the Software is
 16  * furnished to do so, subject to the following conditions:
 17  * 
 18  * The above copyright notice and this permission notice shall be included in
 19  * all copies or substantial portions of the Software.
 20  * 
 21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 27  * THE SOFTWARE.
 28  *
 29  */
 30 
 31 /**
 32  * CCControlPotentiometer: Potentiometer control for Cocos2D.
 33  * @class
 34  * @extends cc.Control
 35  *
 36  * @property {Number}           value           - The current value of the potentionmeter
 37  * @property {Number}           minValue        - The minimum value of the potentionmeter
 38  * @property {Number}           maxValue        - The maximum value of the potentionmeter
 39  * @property {cc.ProgressTimer} progressTimer   - The progress timer of the potentionmeter
 40  * @property {cc.Sprite}        thumbSprite     - The thumb sprite of the potentionmeter
 41  * @property {cc.Point}         prevLocation    - The previous location of the potentionmeter
 42  */
 43 cc.ControlPotentiometer = cc.Control.extend(/** @lends cc.ControlPotentiometer# */{
 44     _thumbSprite:null,
 45     _progressTimer:null,
 46     _previousLocation:null,
 47     /** Contains the receiver’s current value. */
 48     _value:0,
 49     /** Contains the minimum value of the receiver.
 50      * The default value of this property is 0.0. */
 51     _minimumValue:0,
 52     /** Contains the maximum value of the receiver.
 53      * The default value of this property is 1.0. */
 54     _maximumValue:1,
 55     _className:"ControlPotentiometer",
 56 
 57     /**
 58      *
 59      * @param {cc.Sprite} trackSprite
 60      * @param {cc.ProgressTimer}  progressTimer
 61      * @param {cc.Sprite}  thumbSprite
 62      * @return {Boolean}
 63      */
 64     initWithTrackSprite_ProgressTimer_ThumbSprite:function (trackSprite, progressTimer, thumbSprite) {
 65         if (this.init()) {
 66             this.setProgressTimer(progressTimer);
 67             this.setThumbSprite(thumbSprite);
 68             this._thumbSprite.setPosition(progressTimer.getPosition());
 69 
 70             this.addChild(thumbSprite, 2);
 71             this.addChild(progressTimer, 1);
 72             this.addChild(trackSprite);
 73 
 74             this.setContentSize(trackSprite.getContentSize());
 75 
 76             // Init default values
 77             this._minimumValue = 0.0;
 78             this._maximumValue = 1.0;
 79             this.setValue(this._minimumValue);
 80             return true;
 81         }
 82         return false;
 83     },
 84 
 85     setEnabled:function (enabled) {
 86         this.setEnabled(enabled);
 87         if (this._thumbSprite != NULL) {
 88             this._thumbSprite.setOpacity((enabled) ? 255 : 128);
 89         }
 90     },
 91 
 92     setValue:function (value) {
 93         // set new value with sentinel
 94         if (value < this._minimumValue) {
 95             value = this._minimumValue;
 96         }
 97 
 98         if (value > this._maximumValue) {
 99             value = this._maximumValue;
100         }
101 
102         this._value = value;
103 
104         // Update thumb and progress position for new value
105         var percent = (value - this._minimumValue) / (this._maximumValue - this._minimumValue);
106         this._progressTimer.setPercentage(percent * 100.0);
107         this._thumbSprite.setRotation(percent * 360.0);
108 
109         this.sendActionsForControlEvents(cc.CONTROL_EVENT_VALUECHANGED);
110     },
111 
112     getValue:function () {
113         return this._value;
114     },
115 
116     setMinimumValue:function (minimumValue) {
117         this._minimumValue = minimumValue;
118 
119         if (this._minimumValue >= this._maximumValue) {
120             this._maximumValue = this._minimumValue + 1.0;
121         }
122 
123         this.setValue(this._maximumValue);
124     },
125 
126     getMinimumValue:function () {
127         return this._minimumValue;
128     },
129 
130     setMaximumValue:function (maximumValue) {
131         this._maximumValue = maximumValue;
132 
133         if (this._maximumValue <= this._minimumValue) {
134             this._minimumValue = this._maximumValue - 1.0;
135         }
136 
137         this.setValue(this._minimumValue);
138     },
139 
140     getMaximumValue:function () {
141         return this._maximumValue;
142     },
143 
144     isTouchInside:function (touch) {
145         var touchLocation = this.getTouchLocation(touch);
146 
147         var distance = this.distanceBetweenPointAndPoint(this._progressTimer.getPosition(), touchLocation);
148 
149         return distance < Math.min(this.getContentSize().width / 2, this.getContentSize().height / 2);
150     },
151 
152     onTouchBegan:function (touch, event) {
153         if (!this.isTouchInside(touch) || !this.isEnabled() || !this.isVisible()) {
154             return false;
155         }
156 
157         this._previousLocation = this.getTouchLocation(touch);
158 
159         this.potentiometerBegan(this._previousLocation);
160 
161         return true;
162     },
163 
164     onTouchMoved:function (touch, event) {
165         var location = this.getTouchLocation(touch);
166 
167         this.potentiometerMoved(location);
168     },
169 
170     onTouchEnded:function (touch, event) {
171         this.potentiometerEnded(cc.p(0, 0));
172     },
173 
174     /**
175      * the distance between the point1 and point2
176      * @param {cc.Point} point1
177      * @param {cc.Point}  point2
178      * @return {Number}
179      */
180     distanceBetweenPointAndPoint:function (point1, point2) {
181         var dx = point1.x - point2.x;
182         var dy = point1.y - point2.y;
183         return Math.sqrt(dx * dx + dy * dy);
184     },
185 
186     /**
187      * the angle in degree between line1 and line2.
188      * @param {cc.Point}  beginLineA
189      * @param {cc.Point}  endLineA
190      * @param {cc.Point}  beginLineB
191      * @param {cc.Point}  endLineB
192      * @return {Number}
193      */
194     angleInDegreesBetweenLineFromPoint_toPoint_toLineFromPoint_toPoint:function (beginLineA, endLineA, beginLineB, endLineB) {
195         var a = endLineA.x - beginLineA.x;
196         var b = endLineA.y - beginLineA.y;
197         var c = endLineB.x - beginLineB.x;
198         var d = endLineB.y - beginLineB.y;
199 
200         var atanA = Math.atan2(a, b);
201         var atanB = Math.atan2(c, d);
202 
203         // convert radiants to degrees
204         return (atanA - atanB) * 180 / Math.PI;
205     },
206 
207     potentiometerBegan:function (location) {
208         this.setSelected(true);
209         this.getThumbSprite().setColor(cc.color.GRAY);
210     },
211 
212     potentiometerMoved:function (location) {
213         var angle = this.angleInDegreesBetweenLineFromPoint_toPoint_toLineFromPoint_toPoint(this._progressTimer.getPosition(), location, this._progressTimer.getPosition(), this._previousLocation);
214 
215         // fix value, if the 12 o'clock position is between location and previousLocation
216         if (angle > 180) {
217             angle -= 360;
218         }
219         else if (angle < -180) {
220             angle += 360;
221         }
222 
223         this.setValue(this._value + angle / 360.0 * (this._maximumValue - this._minimumValue));
224 
225         this._previousLocation = location;
226     },
227 
228     potentiometerEnded:function (location) {
229         this.getThumbSprite().setColor(cc.color.WHITE);
230         this.setSelected(false);
231     },
232     setThumbSprite:function (sprite) {
233         this._thumbSprite = sprite;
234     },
235     getThumbSprite:function () {
236         return this._thumbSprite;
237     },
238     setProgressTimer:function (sprite) {
239         this._progressTimer = sprite;
240     },
241     getProgressTimer:function () {
242         return this._progressTimer;
243     },
244     setPreviousLocation:function (point) {
245         this._previousLocation = point;
246     },
247     getPreviousLocation:function () {
248         return this._previousLocation;
249     }
250 });
251 
252 var _p = cc.ControlPotentiometer.prototype;
253 
254 // Extended properties
255 /** @expose */
256 _p.value;
257 cc.defineGetterSetter(_p, "value", _p.getValue, _p.setValue);
258 /** @expose */
259 _p.minValue;
260 cc.defineGetterSetter(_p, "minValue", _p.getMinimumValue, _p.setMinimumValue);
261 /** @expose */
262 _p.maxValue;
263 cc.defineGetterSetter(_p, "maxValue", _p.getMaximumValue, _p.setMaximumValue);
264 /** @expose */
265 _p.progressTimer;
266 cc.defineGetterSetter(_p, "progressTimer", _p.getProgressTimer, _p.setProgressTimer);
267 /** @expose */
268 _p.thumbSprite;
269 cc.defineGetterSetter(_p, "thumbSprite", _p.getThumbSprite, _p.setThumbSprite);
270 /** @expose */
271 _p.prevLocation;
272 cc.defineGetterSetter(_p, "prevLocation", _p.getPreviousLocation, _p.setPreviousLocation);
273 
274 _p = null;
275 
276 cc.ControlPotentiometer.create = function (backgroundFile, progressFile, thumbFile) {
277     var pRet = new cc.ControlPotentiometer();
278     if (pRet) {
279         // Prepare track for potentiometer
280         var backgroundSprite = cc.Sprite.create(backgroundFile);
281 
282         // Prepare thumb for potentiometer
283         var thumbSprite = cc.Sprite.create(thumbFile);
284 
285         // Prepare progress for potentiometer
286         var progressTimer = cc.ProgressTimer.create(cc.Sprite.create(progressFile));
287         if (pRet.initWithTrackSprite_ProgressTimer_ThumbSprite(backgroundSprite, progressTimer, thumbSprite)) {
288             return pRet;
289         }
290     }
291     return null;
292 };