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