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  * @ignore
 33  */
 34 cc.CONTROL_STEPPER_PARTMINUS = 0;
 35 cc.CONTROL_STEPPER_PARTPLUS = 1;
 36 cc.CONTROL_STEPPER_PARTNONE = 2;
 37 cc.CONTROL_STEPPER_LABELCOLOR_ENABLED = cc.color(55, 55, 55);
 38 cc.CONTROL_STEPPER_LABELCOLOR_DISABLED = cc.color(147, 147, 147);
 39 cc.CONTROL_STEPPER_LABELFONT = "CourierNewPSMT";
 40 cc.AUTOREPEAT_DELTATIME = 0.15;
 41 cc.AUTOREPEAT_INCREASETIME_INCREMENT = 12;
 42 
 43 /**
 44  * ControlStepper: Stepper ui component.
 45  * @class
 46  * @extends cc.Control
 47  *
 48  * @property {Boolean}      wraps       - Indicate whether the stepper wraps
 49  * @property {Number}       value       - The value of the stepper control
 50  * @property {Number}       minValue    - The minimum value of the stepper control
 51  * @property {Number}       maxValue    - The maximum value of the stepper control
 52  * @property {Number}       stepValue   - The interval value for each step of the stepper control
 53  * @property {Boolean}      continuous  - <@readonly> Indicate whether the stepper value is continuous
 54  * @property {cc.Sprite}    minusSprite - The sprite for minus button of the stepper control
 55  * @property {cc.Sprite}    plusSprite  - The sprite for plus button of the stepper control
 56  * @property {cc.LabelTTF}  minusLabel  - The label for minus button of the stepper control
 57  * @property {cc.LabelTTF}  plusSLabel  - The label for plus button of the stepper control
 58  */
 59 cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{
 60     _minusSprite:null,
 61     _plusSprite:null,
 62     _minusLabel:null,
 63     _plusLabel:null,
 64     _value:0,
 65     _continuous:false,
 66     _autorepeat:false,
 67     _wraps:false,
 68     _minimumValue:0,
 69     _maximumValue:0,
 70     _stepValue:0,
 71     _touchInsideFlag:false,
 72     _touchedPart:cc.CONTROL_STEPPER_PARTNONE,
 73     _autorepeatCount:0,
 74     _className:"ControlStepper",
 75     ctor:function () {
 76         cc.Control.prototype.ctor.call(this);
 77         this._minusSprite = null;
 78         this._plusSprite = null;
 79         this._minusLabel = null;
 80         this._plusLabel = null;
 81         this._value = 0;
 82         this._continuous = false;
 83         this._autorepeat = false;
 84         this._wraps = false;
 85         this._minimumValue = 0;
 86         this._maximumValue = 0;
 87         this._stepValue = 0;
 88         this._touchInsideFlag = false;
 89         this._touchedPart = cc.CONTROL_STEPPER_PARTNONE;
 90         this._autorepeatCount = 0;
 91     },
 92 
 93     initWithMinusSpriteAndPlusSprite:function (minusSprite, plusSprite) {
 94         if(!minusSprite)
 95             throw "cc.ControlStepper.initWithMinusSpriteAndPlusSprite(): Minus sprite should be non-null.";
 96         if(!plusSprite)
 97             throw "cc.ControlStepper.initWithMinusSpriteAndPlusSprite(): Plus sprite should be non-null.";
 98 
 99         if (this.init()) {
100             // Set the default values
101             this._autorepeat = true;
102             this._continuous = true;
103             this._minimumValue = 0;
104             this._maximumValue = 100;
105             this._value = 0;
106             this._stepValue = 1;
107             this._wraps = false;
108             this.ignoreAnchorPointForPosition(false);
109 
110             // Add the minus components
111             this.setMinusSprite(minusSprite);
112             this._minusSprite.setPosition(minusSprite.getContentSize().width / 2, minusSprite.getContentSize().height / 2);
113             this.addChild(this._minusSprite);
114 
115             this.setMinusLabel(cc.LabelTTF.create("-", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER));
116             this._minusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_DISABLED);
117             this._minusLabel.setPosition(this._minusSprite.getContentSize().width / 2, this._minusSprite.getContentSize().height / 2);
118             this._minusSprite.addChild(this._minusLabel);
119 
120             // Add the plus components
121             this.setPlusSprite(plusSprite);
122             this._plusSprite.setPosition(minusSprite.getContentSize().width + plusSprite.getContentSize().width / 2,
123                 minusSprite.getContentSize().height / 2);
124             this.addChild(this._plusSprite);
125 
126             this.setPlusLabel(cc.LabelTTF.create("+", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER));
127             this._plusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
128             this._plusLabel.setPosition(this._plusSprite.getContentSize().width / 2, this._plusSprite.getContentSize().height / 2);
129             this._plusSprite.addChild(this._plusLabel);
130 
131             // Defines the content size
132             var maxRect = cc.ControlUtils.CCRectUnion(this._minusSprite.getBoundingBox(), this._plusSprite.getBoundingBox());
133             this.setContentSize(this._minusSprite.getContentSize().width + this._plusSprite.getContentSize().height, maxRect.height);
134             return true;
135         }
136         return false;
137     },
138 
139 //#pragma mark Properties
140 
141     setWraps: function (wraps) {
142         this._wraps = wraps;
143 
144         if (this._wraps) {
145             this._minusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
146             this._plusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
147         }
148 
149         this.setValue(this._value);
150     },
151 
152 	getWraps: function () {
153 		return this._wraps;
154 	},
155 
156     setMinimumValue:function (minimumValue) {
157         if (minimumValue >= this._maximumValue)
158             throw "cc.ControlStepper.setMinimumValue(): minimumValue should be numerically less than maximumValue.";
159 
160         this._minimumValue = minimumValue;
161         this.setValue(this._value);
162     },
163 	getMinimumValue: function () {
164 		return this._minimumValue;
165 	},
166 
167     setMaximumValue:function (maximumValue) {
168         if (maximumValue <= this._minimumValue)
169             throw "cc.ControlStepper.setMaximumValue(): maximumValue should be numerically less than maximumValue.";
170 
171         this._maximumValue = maximumValue;
172         this.setValue(this._value);
173     },
174 	getMaximumValue: function () {
175 		return this._maximumValue;
176 	},
177 
178     setValue:function (value) {
179         this.setValueWithSendingEvent(value, true);
180     },
181 
182     getValue:function () {
183         return this._value;
184     },
185 
186     setStepValue:function (stepValue) {
187         if (stepValue <= 0)
188             throw "cc.ControlStepper.setMaximumValue(): stepValue should be numerically greater than 0.";
189         this._stepValue = stepValue;
190     },
191 
192 	getStepValue:function () {
193 		return this._stepValue;
194 	},
195 
196     isContinuous:function () {
197         return this._continuous;
198     },
199 
200     setValueWithSendingEvent:function (value, send) {
201         if (value < this._minimumValue) {
202             value = this._wraps ? this._maximumValue : this._minimumValue;
203         } else if (value > this._maximumValue) {
204             value = this._wraps ? this._minimumValue : this._maximumValue;
205         }
206 
207         this._value = value;
208 
209         if (!this._wraps) {
210             this._minusLabel.setColor((value == this._minimumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
211             this._plusLabel.setColor((value == this._maximumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED);
212         }
213 
214         if (send) {
215             this.sendActionsForControlEvents(cc.CONTROL_EVENT_VALUECHANGED);
216         }
217     },
218 
219     startAutorepeat:function () {
220         this._autorepeatCount = -1;
221         this.schedule(this.update, cc.AUTOREPEAT_DELTATIME, cc.REPEAT_FOREVER, cc.AUTOREPEAT_DELTATIME * 3);
222     },
223 
224     /** Stop the autorepeat. */
225     stopAutorepeat:function () {
226         this.unschedule(this.update);
227     },
228 
229     update:function (dt) {
230         this._autorepeatCount++;
231 
232         if ((this._autorepeatCount < cc.AUTOREPEAT_INCREASETIME_INCREMENT) && (this._autorepeatCount % 3) != 0)
233             return;
234 
235         if (this._touchedPart == cc.CONTROL_STEPPER_PARTMINUS) {
236             this.setValueWithSendingEvent(this._value - this._stepValue, this._continuous);
237         } else if (this._touchedPart == cc.CONTROL_STEPPER_PARTPLUS) {
238             this.setValueWithSendingEvent(this._value + this._stepValue, this._continuous);
239         }
240     },
241 
242 //#pragma mark CCControlStepper Private Methods
243 
244     updateLayoutUsingTouchLocation:function (location) {
245         if (location.x < this._minusSprite.getContentSize().width
246             && this._value > this._minimumValue) {
247             this._touchedPart = cc.CONTROL_STEPPER_PARTMINUS;
248             this._minusSprite.setColor(cc.color.GRAY);
249             this._plusSprite.setColor(cc.color.WHITE);
250 
251         } else if (location.x >= this._minusSprite.getContentSize().width
252             && this._value < this._maximumValue) {
253             this._touchedPart = cc.CONTROL_STEPPER_PARTPLUS;
254             this._minusSprite.setColor(cc.color.WHITE);
255             this._plusSprite.setColor(cc.color.GRAY);
256 
257         } else {
258             this._touchedPart = cc.CONTROL_STEPPER_PARTNONE;
259             this._minusSprite.setColor(cc.color.WHITE);
260             this._plusSprite.setColor(cc.color.WHITE);
261         }
262     },
263 
264 
265     onTouchBegan:function (touch, event) {
266         if (!this.isTouchInside(touch) || !this.isEnabled() || !this.isVisible()) {
267             return false;
268         }
269 
270         var location = this.getTouchLocation(touch);
271         this.updateLayoutUsingTouchLocation(location);
272         this._touchInsideFlag = true;
273 
274         if (this._autorepeat) {
275             this.startAutorepeat();
276         }
277 
278         return true;
279     },
280 
281     onTouchMoved:function (touch, event) {
282         if (this.isTouchInside(touch)) {
283             var location = this.getTouchLocation(touch);
284             this.updateLayoutUsingTouchLocation(location);
285 
286             if (!this._touchInsideFlag) {
287                 this._touchInsideFlag = true;
288 
289                 if (this._autorepeat) {
290                     this.startAutorepeat();
291                 }
292             }
293         } else {
294             this._touchInsideFlag = false;
295             this._touchedPart = cc.CONTROL_STEPPER_PARTNONE;
296             this._minusSprite.setColor(cc.color.WHITE);
297             this._plusSprite.setColor(cc.color.WHITE);
298             if (this._autorepeat) {
299                 this.stopAutorepeat();
300             }
301         }
302     },
303 
304     onTouchEnded:function (touch, event) {
305         this._minusSprite.setColor(cc.color.WHITE);
306         this._plusSprite.setColor(cc.color.WHITE);
307 
308         if (this._autorepeat) {
309             this.stopAutorepeat();
310         }
311 
312         if (this.isTouchInside(touch)) {
313             var location = this.getTouchLocation(touch);
314             this.setValue(this._value + ((location.x < this._minusSprite.getContentSize().width) ? (0.0 - this._stepValue) : this._stepValue));
315         }
316     },
317     setMinusSprite:function (sprite) {
318         this._minusSprite = sprite;
319     },
320     getMinusSprite:function () {
321         return this._minusSprite;
322     },
323     setPlusSprite:function (sprite) {
324         this._plusSprite = sprite;
325     },
326     getPlusSprite:function () {
327         return this._plusSprite;
328     },
329     setMinusLabel:function (sprite) {
330         this._minusLabel = sprite;
331     },
332     getMinusLabel:function () {
333         return this._minusLabel;
334     },
335     setPlusLabel:function (sprite) {
336         this._plusLabel = sprite;
337     },
338     getPlusLabel:function () {
339         return this._plusLabel;
340     }
341 });
342 
343 var _p = cc.ControlStepper.prototype;
344 
345 // Extedned properties
346 /** @expose */
347 _p.wraps;
348 cc.defineGetterSetter(_p, "wraps", _p.getWraps, _p.setWraps);
349 /** @expose */
350 _p.value;
351 cc.defineGetterSetter(_p, "value", _p.getValue, _p.setValue);
352 /** @expose */
353 _p.minValue;
354 cc.defineGetterSetter(_p, "minValue", _p.getMinimumValue, _p.setMinimumValue);
355 /** @expose */
356 _p.maxValue;
357 cc.defineGetterSetter(_p, "maxValue", _p.getMaximumValue, _p.setMaximumValue);
358 /** @expose */
359 _p.stepValue;
360 cc.defineGetterSetter(_p, "stepValue", _p.getStepValue, _p.setStepValue);
361 /** @expose */
362 _p.continuous;
363 cc.defineGetterSetter(_p, "continuous", _p.isContinuous);
364 /** @expose */
365 _p.minusSprite;
366 cc.defineGetterSetter(_p, "minusSprite", _p.getMinusSprite, _p.setMinusSprite);
367 /** @expose */
368 _p.plusSprite;
369 cc.defineGetterSetter(_p, "plusSprite", _p.getPlusSprite, _p.setPlusSprite);
370 /** @expose */
371 _p.minusLabel;
372 cc.defineGetterSetter(_p, "minusLabel", _p.getMinusLabel, _p.setMinusLabel);
373 /** @expose */
374 _p.plusLabel;
375 cc.defineGetterSetter(_p, "plusLabel", _p.getPlusLabel, _p.setPlusLabel);
376 
377 _p = null;
378 
379 cc.ControlStepper.create = function (minusSprite, plusSprite) {
380     var pRet = new cc.ControlStepper();
381     if (pRet && pRet.initWithMinusSpriteAndPlusSprite(minusSprite, plusSprite)) {
382         return pRet;
383     }
384     return null;
385 };