1 /**
  2  *
  3  * Copyright (c) 2008-2010 Ricardo Quesada
  4  * Copyright (c) 2011-2012 cocos2d-x.org
  5  * Copyright (c) 2013-2014 Chukong Technologies Inc.
  6  *
  7  * Copyright 2011 Yannick Loriot. All rights reserved.
  8  * http://yannickloriot.com
  9  *
 10  * Permission is hereby granted, free of charge, to any person obtaining a copy
 11  * of this software and associated documentation files (the "Software"), to deal
 12  * in the Software without restriction, including without limitation the rights
 13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 14  * copies of the Software, and to permit persons to whom the Software is
 15  * furnished to do so, subject to the following conditions:
 16  *
 17  * The above copyright notice and this permission notice shall be included in
 18  * all copies or substantial portions of the Software.
 19  *
 20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 26  * THE SOFTWARE.
 27  */
 28 
 29 /**
 30  * CCControlSwitch: Switch control ui component
 31  * @class
 32  * @extends cc.Control
 33  */
 34 cc.ControlSwitch = cc.Control.extend(/** @lends cc.ControlSwitch# */{
 35     /** Sprite which represents the view. */
 36     _switchSprite:null,
 37     _initialTouchXPosition:0,
 38 
 39     _moved:false,
 40     /** A Boolean value that determines the off/on state of the switch. */
 41     _on:false,
 42     _className:"ControlSwitch",
 43     ctor:function (maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel) {
 44         cc.Control.prototype.ctor.call(this);
 45 
 46         offLabel && this.initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel);
 47     },
 48 
 49     /** Creates a switch with a mask sprite, on/off sprites for on/off states, a thumb sprite and an on/off labels. */
 50     initWithMaskSprite:function (maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel) {
 51         if(!maskSprite)
 52             throw "cc.ControlSwitch.initWithMaskSprite(): maskSprite should be non-null.";
 53         if(!onSprite)
 54             throw "cc.ControlSwitch.initWithMaskSprite(): onSprite should be non-null.";
 55         if(!offSprite)
 56             throw "cc.ControlSwitch.initWithMaskSprite(): offSprite should be non-null.";
 57         if(!thumbSprite)
 58             throw "cc.ControlSwitch.initWithMaskSprite(): thumbSprite should be non-null.";
 59         if (this.init()) {
 60             this._on = true;
 61 
 62             this._switchSprite = new cc.ControlSwitchSprite();
 63             this._switchSprite.initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel);
 64             this._switchSprite.setPosition(this._switchSprite.getContentSize().width / 2, this._switchSprite.getContentSize().height / 2);
 65             this.addChild(this._switchSprite);
 66 
 67             this.ignoreAnchorPointForPosition(false);
 68             this.setAnchorPoint(0.5, 0.5);
 69             this.setContentSize(this._switchSprite.getContentSize());
 70             return true;
 71         }
 72         return false;
 73     },
 74 
 75     setOn:function (isOn, animated) {
 76         animated = animated || false;
 77         this._on = isOn;
 78         var xPosition = (this._on) ? this._switchSprite.getOnPosition() : this._switchSprite.getOffPosition();
 79         if(animated){
 80             this._switchSprite.runAction(cc.ActionTween.create(0.2, "sliderXPosition", this._switchSprite.getSliderXPosition(),xPosition));
 81         }else{
 82             this._switchSprite.setSliderXPosition(xPosition);
 83         }
 84         this.sendActionsForControlEvents(cc.CONTROL_EVENT_VALUECHANGED);
 85     },
 86 
 87     isOn:function () {
 88         return this._on;
 89     },
 90 
 91     hasMoved:function () {
 92         return this._moved;
 93     },
 94 
 95     setEnabled:function (enabled) {
 96         this._enabled = enabled;
 97 
 98         this._switchSprite.setOpacity((enabled) ? 255 : 128);
 99     },
100 
101     locationFromTouch:function (touch) {
102         var touchLocation = touch.getLocation();                      // Get the touch position
103         touchLocation = this.convertToNodeSpace(touchLocation);                  // Convert to the node space of this class
104 
105         return touchLocation;
106     },
107 
108     onTouchBegan:function (touch, event) {
109         if (!this.isTouchInside(touch)  || !this.isEnabled()|| !this.isVisible()) {
110             return false;
111         }
112 
113         this._moved = false;
114 
115         var location = this.locationFromTouch(touch);
116 
117         this._initialTouchXPosition = location.x - this._switchSprite.getSliderXPosition();
118 
119         this._switchSprite.getThumbSprite().setColor(cc.color.GRAY);
120         this._switchSprite.needsLayout();
121 
122         return true;
123     },
124 
125     onTouchMoved:function (touch, event) {
126         var location = this.locationFromTouch(touch);
127         location = cc.p(location.x - this._initialTouchXPosition, 0);
128 
129         this._moved = true;
130 
131         this._switchSprite.setSliderXPosition(location.x);
132     },
133 
134     onTouchEnded:function (touch, event) {
135         var location = this.locationFromTouch(touch);
136 
137         this._switchSprite.getThumbSprite().setColor(cc.color.WHITE);
138 
139         if (this.hasMoved()) {
140             this.setOn(!(location.x < this._switchSprite.getContentSize().width / 2), true);
141         } else {
142             this.setOn(!this._on, true);
143         }
144     },
145 
146     onTouchCancelled:function (touch, event) {
147         var location = this.locationFromTouch(touch);
148 
149         this._switchSprite.getThumbSprite().setColor(cc.color.WHITE);
150 
151         if (this.hasMoved()) {
152             this.setOn(!(location.x < this._switchSprite.getContentSize().width / 2), true);
153         } else {
154             this.setOn(!this._on, true);
155         }
156     }
157 });
158 
159 /** Creates a switch with a mask sprite, on/off sprites for on/off states and a thumb sprite.
160  *  @deprecated
161  */
162 cc.ControlSwitch.create = function (maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel) {
163     return new cc.ControlSwitch(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel);
164 };
165 
166 /**
167  * ControlSwitchSprite: Sprite switch control ui component
168  * @class
169  * @extends cc.Sprite
170  *
171  * @property {Number}           sliderX         - Slider's x position
172  * @property {cc.Point}         onPos           - The position of slider when switch is on
173  * @property {cc.Point}         offPos          - The position of slider when switch is off
174  * @property {cc.Texture2D}     maskTexture     - The texture of the mask
175  * @property {cc.Point}         texturePos      - The position of the texture
176  * @property {cc.Point}         maskPos         - The position of the mask
177  * @property {cc.Sprite}        onSprite        - The sprite of switch on
178  * @property {cc.Sprite}        offSprite       - The sprite of switch off
179  * @property {cc.Sprite}        thumbSprite     - The thumb sprite of the switch control
180  * @property {cc.LabelTTF}      onLabel         - The sprite of switch on
181  * @property {cc.LabelTTF}      offLabel        - The sprite of switch off
182  * @property {Number}           onSideWidth     - <@readonly> The width of the on side of the switch control
183  * @property {Number}           offSideWidth    - <@readonly> The width of the off side of the switch control
184  */
185 cc.ControlSwitchSprite = cc.Sprite.extend({
186     _sliderXPosition:0,
187     _onPosition:0,
188     _offPosition:0,
189 
190     _textureLocation:0,
191     _maskLocation:0,
192     _maskSize:null,
193 
194     _onSprite:null,
195     _offSprite:null,
196     _thumbSprite:null,
197     _onLabel:null,
198     _offLabel:null,
199     _clipper:null,
200     _stencil:null,
201     _backRT:null,
202 
203     ctor:function () {
204         cc.Sprite.prototype.ctor.call(this);
205         this._sliderXPosition = 0;
206         this._onPosition = 0;
207         this._offPosition = 0;
208         this._maskLocation = 0;
209         this._maskSize = cc.size(0, 0);
210         this._onSprite = null;
211         this._offSprite = null;
212         this._thumbSprite = null;
213         this._onLabel = null;
214         this._offLabel = null;
215     },
216 
217     initWithMaskSprite:function (maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel) {
218         if (cc.Sprite.prototype.initWithTexture.call(this, maskSprite.getTexture())) {
219             // Sets the default values
220             this._onPosition = 0;
221             this._offPosition = -onSprite.getContentSize().width + thumbSprite.getContentSize().width / 2;
222             this._sliderXPosition = this._onPosition;
223 
224             this.setOnSprite(onSprite);
225             this.setOffSprite(offSprite);
226             this.setThumbSprite(thumbSprite);
227             this.setOnLabel(onLabel);
228             this.setOffLabel(offLabel);
229 
230             // Set up the mask with the Mask shader
231             this._stencil = maskSprite;
232             var maskSize = this._maskSize = this._stencil.getContentSize();
233             this._stencil.setPosition(0, 0);
234 
235             // Init clipper for mask
236             this._clipper = cc.ClippingNode.create();
237             this._clipper.setAnchorPoint(0.5, 0.5);
238             this._clipper.setPosition(maskSize.width / 2, maskSize.height / 2);
239             this._clipper.setStencil(this._stencil);
240             this.addChild(this._clipper);
241 
242             this._clipper.addChild(onSprite);
243             this._clipper.addChild(offSprite);
244             this._clipper.addChild(onLabel);
245             this._clipper.addChild(offLabel);
246 
247             this.addChild(this._thumbSprite);
248 
249             this.needsLayout();
250             return true;
251         }
252         return false;
253     },
254 
255     needsLayout:function () {
256         var maskSize = this._maskSize;
257         this._onSprite.setPosition(
258             this._onSprite.getContentSize().width / 2 + this._sliderXPosition - maskSize.width / 2,
259             this._onSprite.getContentSize().height / 2 - maskSize.height / 2
260         );
261         this._offSprite.setPosition(
262             this._onSprite.getContentSize().width + this._offSprite.getContentSize().width / 2 + this._sliderXPosition - maskSize.width / 2,
263             this._offSprite.getContentSize().height / 2 - maskSize.height / 2
264         );
265 
266         if (this._onLabel) {
267             this._onLabel.setPosition(
268                 this._onSprite.getPositionX() - this._thumbSprite.getContentSize().width / 6,
269                 this._onSprite.getContentSize().height / 2 - maskSize.height / 2
270             );
271         }
272         if (this._offLabel) {
273             this._offLabel.setPosition(
274                 this._offSprite.getPositionX() + this._thumbSprite.getContentSize().width / 6,
275                 this._offSprite.getContentSize().height / 2 - maskSize.height / 2
276             );
277         }
278         this._thumbSprite.setPosition(
279             this._onSprite.getContentSize().width + this._sliderXPosition,
280             this._maskSize.height / 2
281         );
282     },
283 
284     setSliderXPosition:function (sliderXPosition) {
285         if (sliderXPosition <= this._offPosition) {
286             // Off
287             sliderXPosition = this._offPosition;
288         } else if (sliderXPosition >= this._onPosition) {
289             // On
290             sliderXPosition = this._onPosition;
291         }
292 
293         this._sliderXPosition = sliderXPosition;
294 
295         this.needsLayout();
296     },
297     getSliderXPosition:function () {
298         return this._sliderXPosition;
299     },
300 
301     _getOnSideWidth:function () {
302         return this._onSprite.getContentSize().width;
303     },
304 
305     _getOffSideWidth:function () {
306         return this._offSprite.getContentSize().height;
307     },
308 
309     updateTweenAction:function (value, key) {
310         cc.log("key = " + key + ", value = " + value);
311         this.setSliderXPosition(value);
312     },
313 
314     setOnPosition:function (onPosition) {
315         this._onPosition = onPosition;
316     },
317     getOnPosition:function () {
318         return this._onPosition;
319     },
320 
321     setOffPosition:function (offPosition) {
322         this._offPosition = offPosition;
323     },
324     getOffPosition:function () {
325         return this._offPosition;
326     },
327 
328     setMaskTexture:function (maskTexture) {
329         this._stencil.setTexture(maskTexture);
330     },
331     getMaskTexture:function () {
332         return this._stencil.getTexture();
333     },
334 
335     setTextureLocation:function (textureLocation) {
336         this._textureLocation = textureLocation;
337     },
338     getTextureLocation:function () {
339         return this._textureLocation;
340     },
341 
342     setMaskLocation:function (maskLocation) {
343         this._maskLocation = maskLocation;
344     },
345     getMaskLocation:function () {
346         return this._maskLocation;
347     },
348 
349     setOnSprite:function (onSprite) {
350         this._onSprite = onSprite;
351     },
352     getOnSprite:function () {
353         return this._onSprite;
354     },
355 
356     setOffSprite:function (offSprite) {
357         this._offSprite = offSprite;
358     },
359     getOffSprite:function () {
360         return this._offSprite;
361     },
362 
363     setThumbSprite:function (thumbSprite) {
364         this._thumbSprite = thumbSprite;
365     },
366     getThumbSprite:function () {
367         return this._thumbSprite;
368     },
369 
370     setOnLabel:function (onLabel) {
371         this._onLabel = onLabel;
372     },
373     getOnLabel:function () {
374         return this._onLabel;
375     },
376 
377     setOffLabel:function (offLabel) {
378         this._offLabel = offLabel;
379     },
380     getOffLabel:function () {
381         return this._offLabel;
382     }
383 });
384 
385 var _p = cc.ControlSwitchSprite.prototype;
386 
387 /** @expose */
388 _p.sliderX;
389 cc.defineGetterSetter(_p, "sliderX", _p.getSliderXPosition, _p.setSliderXPosition);
390 /** @expose */
391 _p.onPos;
392 cc.defineGetterSetter(_p, "onPos", _p.getOnPosition, _p.setOnPosition);
393 /** @expose */
394 _p.offPos;
395 cc.defineGetterSetter(_p, "offPos", _p.getOffPosition, _p.setOffPosition);
396 /** @expose */
397 _p.maskTexture;
398 cc.defineGetterSetter(_p, "maskTexture", _p.getMaskTexture, _p.setMaskTexture);
399 /** @expose */
400 _p.maskPos;
401 cc.defineGetterSetter(_p, "maskPos", _p.getMaskLocation, _p.setMaskLocation);
402 /** @expose */
403 _p.onSprite;
404 cc.defineGetterSetter(_p, "onSprite", _p.getOnSprite, _p.setOnSprite);
405 /** @expose */
406 _p.offSprite;
407 cc.defineGetterSetter(_p, "offSprite", _p.getOffSprite, _p.setOffSprite);
408 /** @expose */
409 _p.thumbSprite;
410 cc.defineGetterSetter(_p, "thumbSprite", _p.getThumbSprite, _p.setThumbSprite);
411 /** @expose */
412 _p.onLabel;
413 cc.defineGetterSetter(_p, "onLabel", _p.getOnLabel, _p.setOnLabel);
414 /** @expose */
415 _p.offLabel;
416 cc.defineGetterSetter(_p, "offLabel", _p.getOffLabel, _p.setOffLabel);
417 /** @expose */
418 _p.onSideWidth;
419 cc.defineGetterSetter(_p, "onSideWidth", _p._getOnSideWidth);
420 /** @expose */
421 _p.offSideWidth;
422 cc.defineGetterSetter(_p, "offSideWidth", _p._getOffSideWidth);
423 
424 _p = null;
425