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