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 cc.CONTROL_STEPPER_PARTMINUS = 0;
 29 cc.CONTROL_STEPPER_PARTPLUS = 1;
 30 cc.CONTROL_STEPPER_PARTNONE = 2;
 31 cc.CONTROL_STEPPER_LABELCOLOR_ENABLED = cc.c3b(55, 55, 55);
 32 cc.CONTROL_STEPPER_LABELCOLOR_DISABLED = cc.c3b(147, 147, 147);
 33 cc.CONTROL_STEPPER_LABELFONT = "CourierNewPSMT";
 34 cc.AUTOREPEAT_DELTATIME = 0.15;
 35 cc.AUTOREPEAT_INCREASETIME_INCREMENT = 12;
 36 
 37 /**
 38  * ControlStepper  control for Cocos2D.
 39  * @class
 40  * @extends cc.Control
 41  */
 42 cc.ControlStepper = cc.Control.extend({
 43     _minusSprite:null,
 44     _plusSprite:null,
 45     _minusLabel:null,
 46     _plusLabel:null,
 47     _value:0,
 48     _continuous:false,
 49     _autorepeat:false,
 50     _wraps:false,
 51     _minimumValue:0,
 52     _maximumValue:0,
 53     _stepValue:0,
 54     _touchInsideFlag:false,
 55     _touchedPart:cc.CONTROL_STEPPER_PARTNONE,
 56     _autorepeatCount:0,
 57     ctor:function () {
 58         cc.Control.prototype.ctor.call(this);
 59         this._minusSprite = null;
 60         this._plusSprite = null;
 61         this._minusLabel = null;
 62         this._plusLabel = null;
 63         this._value = 0;
 64         this._continuous = false;
 65         this._autorepeat = false;
 66         this._wraps = false;
 67         this._minimumValue = 0;
 68         this._maximumValue = 0;
 69         this._stepValue = 0;
 70         this._touchInsideFlag = false;
 71         this._touchedPart = cc.CONTROL_STEPPER_PARTNONE;
 72         this._autorepeatCount = 0;
 73     },
 74 
 75     initWithMinusSpriteAndPlusSprite:function (minusSprite, plusSprite) {
 76         if(!minusSprite)
 77             throw "cc.ControlStepper.initWithMinusSpriteAndPlusSprite(): Minus sprite should be non-null.";
 78         if(!plusSprite)
 79             throw "cc.ControlStepper.initWithMinusSpriteAndPlusSprite(): Plus sprite should be non-null.";
 80 
 81         if (this.init()) {
 82             this.setTouchEnabled(true);
 83 
 84             // Set the default values
 85             this._autorepeat = true;
 86             this._continuous = true;
 87             this._minimumValue = 0;
 88             this._maximumValue = 100;
 89             this._value = 0;
 90             this._stepValue = 1;
 91             this._wraps = false;
 92             this.ignoreAnchorPointForPosition(false);
 93 
 94             // Add the minus components
 95             this.setMinusSprite(minusSprite);
 96             this._minusSprite.setPosition(minusSprite.getContentSize().width / 2, minusSprite.getContentSize().height / 2);
 97             this.addChild(this._minusSprite);
 98 
 99             this.setMinusLabel(cc.LabelTTF.create("-", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER));
100             this._minusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_DISABLED);
101             this._minusLabel.setPosition(this._minusSprite.getContentSize().width / 2, this._minusSprite.getContentSize().height / 2);
102             this._minusSprite.addChild(this._minusLabel);
103 
104             // Add the plus components
105             this.setPlusSprite(plusSprite);
106             this._plusSprite.setPosition(minusSprite.getContentSize().width + plusSprite.getContentSize().width / 2,
107                 minusSprite.getContentSize().height / 2);
108             this.addChild(this._plusSprite);
109 
110             this.setPlusLabel(cc.LabelTTF.create("+", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER));
111             this._plusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
112             this._plusLabel.setPosition(this._plusSprite.getContentSize().width / 2, this._plusSprite.getContentSize().height / 2);
113             this._plusSprite.addChild(this._plusLabel);
114 
115             // Defines the content size
116             var maxRect = cc.ControlUtils.CCRectUnion(this._minusSprite.getBoundingBox(), this._plusSprite.getBoundingBox());
117             this.setContentSize(this._minusSprite.getContentSize().width + this._plusSprite.getContentSize().height, maxRect._size.height);
118             return true;
119         }
120         return false;
121     },
122 
123 //#pragma mark Properties
124 
125     setWraps:function (wraps) {
126         this._wraps = wraps;
127 
128         if (this._wraps) {
129             this._minusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
130             this._plusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
131         }
132 
133         this.setValue(this._value);
134     },
135 
136     setMinimumValue:function (minimumValue) {
137         if (minimumValue >= this._maximumValue)
138             throw "cc.ControlStepper.setMinimumValue(): minimumValue should be numerically less than maximumValue.";
139 
140         this._minimumValue = minimumValue;
141         this.setValue(this._value);
142     },
143 
144     setMaximumValue:function (maximumValue) {
145         if (maximumValue <= this._minimumValue)
146             throw "cc.ControlStepper.setMaximumValue(): maximumValue should be numerically less than maximumValue.";
147 
148         this._maximumValue = maximumValue;
149         this.setValue(this._value);
150     },
151 
152     setValue:function (value) {
153         this.setValueWithSendingEvent(value, true);
154     },
155 
156     getValue:function () {
157         return this._value;
158     },
159 
160     setStepValue:function (stepValue) {
161         if (stepValue <= 0)
162             throw "cc.ControlStepper.setMaximumValue(): stepValue should be numerically greater than 0.";
163         this._stepValue = stepValue;
164     },
165 
166     isContinuous:function () {
167         return this._continuous;
168     },
169 
170     setValueWithSendingEvent:function (value, send) {
171         if (value < this._minimumValue) {
172             value = this._wraps ? this._maximumValue : this._minimumValue;
173         } else if (value > this._maximumValue) {
174             value = this._wraps ? this._minimumValue : this._maximumValue;
175         }
176 
177         this._value = value;
178 
179         if (!this._wraps) {
180             this._minusLabel.setColor((value == this._minimumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
181             this._plusLabel.setColor((value == this._maximumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
182         }
183 
184         if (send) {
185             this.sendActionsForControlEvents(cc.CONTROL_EVENT_VALUECHANGED);
186         }
187     },
188 
189     startAutorepeat:function () {
190         this._autorepeatCount = -1;
191         this.schedule(this.update, cc.AUTOREPEAT_DELTATIME, cc.REPEAT_FOREVER, cc.AUTOREPEAT_DELTATIME * 3);
192     },
193 
194     /** Stop the autorepeat. */
195     stopAutorepeat:function () {
196         this.unschedule(this.update);
197     },
198 
199     update:function (dt) {
200         this._autorepeatCount++;
201 
202         if ((this._autorepeatCount < cc.AUTOREPEAT_INCREASETIME_INCREMENT) && (this._autorepeatCount % 3) != 0)
203             return;
204 
205         if (this._touchedPart == cc.CONTROL_STEPPER_PARTMINUS) {
206             this.setValueWithSendingEvent(this._value - this._stepValue, this._continuous);
207         } else if (this._touchedPart == cc.CONTROL_STEPPER_PARTPLUS) {
208             this.setValueWithSendingEvent(this._value + this._stepValue, this._continuous);
209         }
210     },
211 
212 //#pragma mark CCControlStepper Private Methods
213 
214     updateLayoutUsingTouchLocation:function (location) {
215         if (location.x < this._minusSprite.getContentSize().width
216             && this._value > this._minimumValue) {
217             this._touchedPart = cc.CONTROL_STEPPER_PARTMINUS;
218             this._minusSprite.setColor(cc.gray());
219             this._plusSprite.setColor(cc.white());
220 
221         } else if (location.x >= this._minusSprite.getContentSize().width
222             && this._value < this._maximumValue) {
223             this._touchedPart = cc.CONTROL_STEPPER_PARTPLUS;
224             this._minusSprite.setColor(cc.white());
225             this._plusSprite.setColor(cc.gray());
226 
227         } else {
228             this._touchedPart = cc.CONTROL_STEPPER_PARTNONE;
229             this._minusSprite.setColor(cc.white());
230             this._plusSprite.setColor(cc.white());
231         }
232     },
233 
234 
235     onTouchBegan:function (touch, event) {
236         if (!this.isTouchInside(touch) || !this.isEnabled() || !this.isVisible()) {
237             return false;
238         }
239 
240         var location = this.getTouchLocation(touch);
241         this.updateLayoutUsingTouchLocation(location);
242         this._touchInsideFlag = true;
243 
244         if (this._autorepeat) {
245             this.startAutorepeat();
246         }
247 
248         return true;
249     },
250 
251     onTouchMoved:function (touch, event) {
252         if (this.isTouchInside(touch)) {
253             var location = this.getTouchLocation(touch);
254             this.updateLayoutUsingTouchLocation(location);
255 
256             if (!this._touchInsideFlag) {
257                 this._touchInsideFlag = true;
258 
259                 if (this._autorepeat) {
260                     this.startAutorepeat();
261                 }
262             }
263         } else {
264             this._touchInsideFlag = false;
265             this._touchedPart = cc.CONTROL_STEPPER_PARTNONE;
266             this._minusSprite.setColor(cc.white());
267             this._plusSprite.setColor(cc.white());
268             if (this._autorepeat) {
269                 this.stopAutorepeat();
270             }
271         }
272     },
273 
274     onTouchEnded:function (touch, event) {
275         this._minusSprite.setColor(cc.white());
276         this._plusSprite.setColor(cc.white());
277 
278         if (this._autorepeat) {
279             this.stopAutorepeat();
280         }
281 
282         if (this.isTouchInside(touch)) {
283             var location = this.getTouchLocation(touch);
284             this.setValue(this._value + ((location.x < this._minusSprite.getContentSize().width) ? (0.0 - this._stepValue) : this._stepValue));
285         }
286     },
287     setMinusSprite:function (sprite) {
288         this._minusSprite = sprite;
289     },
290     getMinusSprite:function () {
291         return this._minusSprite;
292     },
293     setPlusSprite:function (sprite) {
294         this._plusSprite = sprite;
295     },
296     getPlusSprite:function () {
297         return this._plusSprite;
298     },
299     setMinusLabel:function (sprite) {
300         this._minusLabel = sprite;
301     },
302     getMinusLabel:function () {
303         return this._minusLabel;
304     },
305     setPlusLabel:function (sprite) {
306         this._plusLabel = sprite;
307     },
308     getPlusLabel:function () {
309         return this._plusLabel;
310     }
311 });
312 
313 cc.ControlStepper.create = function (minusSprite, plusSprite) {
314     var pRet = new cc.ControlStepper();
315     if (pRet && pRet.initWithMinusSpriteAndPlusSprite(minusSprite, plusSprite)) {
316         return pRet;
317     }
318     return null;
319 };