1 /**
  2  * Copyright (c) 2012 cocos2d-x.org
  3  * http://www.cocos2d-x.org
  4  *
  5  * Copyright 2012 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 
 28 /**
 29  * CCControlPotentiometer: Potentiometer control for Cocos2D.
 30  * @class
 31  * @extends cc.Control
 32  *
 33  * @property {Number}           value           - The current value of the potentionmeter
 34  * @property {Number}           minValue        - The minimum value of the potentionmeter
 35  * @property {Number}           maxValue        - The maximum value of the potentionmeter
 36  * @property {cc.ProgressTimer} progressTimer   - The progress timer of the potentionmeter
 37  * @property {cc.Sprite}        thumbSprite     - The thumb sprite of the potentionmeter
 38  * @property {cc.Point}         prevLocation    - The previous location of the potentionmeter
 39  */
 40 cc.ControlPotentiometer = cc.Control.extend(/** @lends cc.ControlPotentiometer# */{
 41     _thumbSprite:null,
 42     _progressTimer:null,
 43     _previousLocation:null,
 44     /** Contains the receiver’s current value. */
 45     _value:0,
 46     /** Contains the minimum value of the receiver.
 47      * The default value of this property is 0.0. */
 48     _minimumValue:0,
 49     /** Contains the maximum value of the receiver.
 50      * The default value of this property is 1.0. */
 51     _maximumValue:1,
 52     _className:"ControlPotentiometer",
 53 
 54     /**
 55      *
 56      * @param {cc.Sprite} trackSprite
 57      * @param {cc.ProgressTimer}  progressTimer
 58      * @param {cc.Sprite}  thumbSprite
 59      * @return {Boolean}
 60      */
 61     initWithTrackSprite_ProgressTimer_ThumbSprite:function (trackSprite, progressTimer, thumbSprite) {
 62         if (this.init()) {
 63             this.setProgressTimer(progressTimer);
 64             this.setThumbSprite(thumbSprite);
 65             this._thumbSprite.setPosition(progressTimer.getPosition());
 66 
 67             this.addChild(thumbSprite, 2);
 68             this.addChild(progressTimer, 1);
 69             this.addChild(trackSprite);
 70 
 71             this.setContentSize(trackSprite.getContentSize());
 72 
 73             // Init default values
 74             this._minimumValue = 0.0;
 75             this._maximumValue = 1.0;
 76             this.setValue(this._minimumValue);
 77             return true;
 78         }
 79         return false;
 80     },
 81 
 82     setEnabled:function (enabled) {
 83         this.setEnabled(enabled);
 84         if (this._thumbSprite != NULL) {
 85             this._thumbSprite.setOpacity((enabled) ? 255 : 128);
 86         }
 87     },
 88 
 89     setValue:function (value) {
 90         // set new value with sentinel
 91         if (value < this._minimumValue) {
 92             value = this._minimumValue;
 93         }
 94 
 95         if (value > this._maximumValue) {
 96             value = this._maximumValue;
 97         }
 98 
 99         this._value = value;
100 
101         // Update thumb and progress position for new value
102         var percent = (value - this._minimumValue) / (this._maximumValue - this._minimumValue);
103         this._progressTimer.setPercentage(percent * 100.0);
104         this._thumbSprite.setRotation(percent * 360.0);
105 
106         this.sendActionsForControlEvents(cc.CONTROL_EVENT_VALUECHANGED);
107     },
108 
109     getValue:function () {
110         return this._value;
111     },
112 
113     setMinimumValue:function (minimumValue) {
114         this._minimumValue = minimumValue;
115 
116         if (this._minimumValue >= this._maximumValue) {
117             this._maximumValue = this._minimumValue + 1.0;
118         }
119 
120         this.setValue(this._maximumValue);
121     },
122 
123     getMinimumValue:function () {
124         return this._minimumValue;
125     },
126 
127     setMaximumValue:function (maximumValue) {
128         this._maximumValue = maximumValue;
129 
130         if (this._maximumValue <= this._minimumValue) {
131             this._minimumValue = this._maximumValue - 1.0;
132         }
133 
134         this.setValue(this._minimumValue);
135     },
136 
137     getMaximumValue:function () {
138         return this._maximumValue;
139     },
140 
141     isTouchInside:function (touch) {
142         var touchLocation = this.getTouchLocation(touch);
143 
144         var distance = this.distanceBetweenPointAndPoint(this._progressTimer.getPosition(), touchLocation);
145 
146         return distance < Math.min(this.getContentSize().width / 2, this.getContentSize().height / 2);
147     },
148 
149     onTouchBegan:function (touch, event) {
150         if (!this.isTouchInside(touch) || !this.isEnabled() || !this.isVisible()) {
151             return false;
152         }
153 
154         this._previousLocation = this.getTouchLocation(touch);
155 
156         this.potentiometerBegan(this._previousLocation);
157 
158         return true;
159     },
160 
161     onTouchMoved:function (touch, event) {
162         var location = this.getTouchLocation(touch);
163 
164         this.potentiometerMoved(location);
165     },
166 
167     onTouchEnded:function (touch, event) {
168         this.potentiometerEnded(cc.p(0, 0));
169     },
170 
171     /**
172      * the distance between the point1 and point2
173      * @param {cc.Point} point1
174      * @param {cc.Point}  point2
175      * @return {Number}
176      */
177     distanceBetweenPointAndPoint:function (point1, point2) {
178         var dx = point1.x - point2.x;
179         var dy = point1.y - point2.y;
180         return Math.sqrt(dx * dx + dy * dy);
181     },
182 
183     /**
184      * the angle in degree between line1 and line2.
185      * @param {cc.Point}  beginLineA
186      * @param {cc.Point}  endLineA
187      * @param {cc.Point}  beginLineB
188      * @param {cc.Point}  endLineB
189      * @return {Number}
190      */
191     angleInDegreesBetweenLineFromPoint_toPoint_toLineFromPoint_toPoint:function (beginLineA, endLineA, beginLineB, endLineB) {
192         var a = endLineA.x - beginLineA.x;
193         var b = endLineA.y - beginLineA.y;
194         var c = endLineB.x - beginLineB.x;
195         var d = endLineB.y - beginLineB.y;
196 
197         var atanA = Math.atan2(a, b);
198         var atanB = Math.atan2(c, d);
199 
200         // convert radiants to degrees
201         return (atanA - atanB) * 180 / Math.PI;
202     },
203 
204     potentiometerBegan:function (location) {
205         this.setSelected(true);
206         this.getThumbSprite().setColor(cc.color.GRAY);
207     },
208 
209     potentiometerMoved:function (location) {
210         var angle = this.angleInDegreesBetweenLineFromPoint_toPoint_toLineFromPoint_toPoint(this._progressTimer.getPosition(), location, this._progressTimer.getPosition(), this._previousLocation);
211 
212         // fix value, if the 12 o'clock position is between location and previousLocation
213         if (angle > 180) {
214             angle -= 360;
215         }
216         else if (angle < -180) {
217             angle += 360;
218         }
219 
220         this.setValue(this._value + angle / 360.0 * (this._maximumValue - this._minimumValue));
221 
222         this._previousLocation = location;
223     },
224 
225     potentiometerEnded:function (location) {
226         this.getThumbSprite().setColor(cc.color.WHITE);
227         this.setSelected(false);
228     },
229     setThumbSprite:function (sprite) {
230         this._thumbSprite = sprite;
231     },
232     getThumbSprite:function () {
233         return this._thumbSprite;
234     },
235     setProgressTimer:function (sprite) {
236         this._progressTimer = sprite;
237     },
238     getProgressTimer:function () {
239         return this._progressTimer;
240     },
241     setPreviousLocation:function (point) {
242         this._previousLocation = point;
243     },
244     getPreviousLocation:function () {
245         return this._previousLocation;
246     }
247 });
248 
249 window._p = cc.ControlPotentiometer.prototype;
250 
251 // Extended properties
252 /** @expose */
253 _p.value;
254 cc.defineGetterSetter(_p, "value", _p.getValue, _p.setValue);
255 /** @expose */
256 _p.minValue;
257 cc.defineGetterSetter(_p, "minValue", _p.getMinimumValue, _p.setMinimumValue);
258 /** @expose */
259 _p.maxValue;
260 cc.defineGetterSetter(_p, "maxValue", _p.getMaximumValue, _p.setMaximumValue);
261 /** @expose */
262 _p.progressTimer;
263 cc.defineGetterSetter(_p, "progressTimer", _p.getProgressTimer, _p.setProgressTimer);
264 /** @expose */
265 _p.thumbSprite;
266 cc.defineGetterSetter(_p, "thumbSprite", _p.getThumbSprite, _p.setThumbSprite);
267 /** @expose */
268 _p.prevLocation;
269 cc.defineGetterSetter(_p, "prevLocation", _p.getPreviousLocation, _p.setPreviousLocation);
270 
271 delete window._p;
272 
273 cc.ControlPotentiometer.create = function (backgroundFile, progressFile, thumbFile) {
274     var pRet = new cc.ControlPotentiometer();
275     if (pRet) {
276         // Prepare track for potentiometer
277         var backgroundSprite = cc.Sprite.create(backgroundFile);
278 
279         // Prepare thumb for potentiometer
280         var thumbSprite = cc.Sprite.create(thumbFile);
281 
282         // Prepare progress for potentiometer
283         var progressTimer = cc.ProgressTimer.create(cc.Sprite.create(progressFile));
284         if (pRet.initWithTrackSprite_ProgressTimer_ThumbSprite(backgroundSprite, progressTimer, thumbSprite)) {
285             return pRet;
286         }
287     }
288     return null;
289 };