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