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 new Error("cc.ControlSwitch.initWithMaskSprite(): maskSprite should be non-null.");
 53         if(!onSprite)
 54             throw new Error("cc.ControlSwitch.initWithMaskSprite(): onSprite should be non-null.");
 55         if(!offSprite)
 56             throw new Error("cc.ControlSwitch.initWithMaskSprite(): offSprite should be non-null.");
 57         if(!thumbSprite)
 58             throw new Error("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(new cc.ActionTween(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.init.call(this)) {
219             this.setSpriteFrame(maskSprite.displayFrame());
220             // Sets the default values
221             this._onPosition = 0;
222             this._offPosition = -onSprite.getContentSize().width + thumbSprite.getContentSize().width / 2;
223             this._sliderXPosition = this._onPosition;
224 
225             this.setOnSprite(onSprite);
226             this.setOffSprite(offSprite);
227             this.setThumbSprite(thumbSprite);
228             this.setOnLabel(onLabel);
229             this.setOffLabel(offLabel);
230 
231             // Set up the mask with the Mask shader
232             this._stencil = maskSprite;
233             var maskSize = this._maskSize = this._stencil.getContentSize();
234             this._stencil.setPosition(0, 0);
235 
236             // Init clipper for mask
237             this._clipper = new cc.ClippingNode();
238             this._clipper.setAnchorPoint(0.5, 0.5);
239             this._clipper.setPosition(maskSize.width / 2, maskSize.height / 2);
240             this._clipper.setStencil(this._stencil);
241             this.addChild(this._clipper);
242 
243             this._clipper.addChild(onSprite);
244             this._clipper.addChild(offSprite);
245             this._clipper.addChild(onLabel);
246             this._clipper.addChild(offLabel);
247 
248             this.addChild(this._thumbSprite);
249 
250             this.needsLayout();
251             return true;
252         }
253         return false;
254     },
255 
256     needsLayout:function () {
257         var maskSize = this._maskSize;
258         this._onSprite.setPosition(
259             this._onSprite.getContentSize().width / 2 + this._sliderXPosition - maskSize.width / 2,
260             this._onSprite.getContentSize().height / 2 - maskSize.height / 2
261         );
262         this._offSprite.setPosition(
263             this._onSprite.getContentSize().width + this._offSprite.getContentSize().width / 2 + this._sliderXPosition - maskSize.width / 2,
264             this._offSprite.getContentSize().height / 2 - maskSize.height / 2
265         );
266 
267         if (this._onLabel) {
268             this._onLabel.setPosition(
269                 this._onSprite.getPositionX() - this._thumbSprite.getContentSize().width / 6,
270                 this._onSprite.getContentSize().height / 2 - maskSize.height / 2
271             );
272         }
273         if (this._offLabel) {
274             this._offLabel.setPosition(
275                 this._offSprite.getPositionX() + this._thumbSprite.getContentSize().width / 6,
276                 this._offSprite.getContentSize().height / 2 - maskSize.height / 2
277             );
278         }
279         this._thumbSprite.setPosition(
280             this._onSprite.getContentSize().width + this._sliderXPosition,
281             this._maskSize.height / 2
282         );
283     },
284 
285     setSliderXPosition:function (sliderXPosition) {
286         if (sliderXPosition <= this._offPosition) {
287             // Off
288             sliderXPosition = this._offPosition;
289         } else if (sliderXPosition >= this._onPosition) {
290             // On
291             sliderXPosition = this._onPosition;
292         }
293 
294         this._sliderXPosition = sliderXPosition;
295 
296         this.needsLayout();
297     },
298     getSliderXPosition:function () {
299         return this._sliderXPosition;
300     },
301 
302     _getOnSideWidth:function () {
303         return this._onSprite.getContentSize().width;
304     },
305 
306     _getOffSideWidth:function () {
307         return this._offSprite.getContentSize().height;
308     },
309 
310     updateTweenAction:function (value, key) {
311         if (key === "sliderXPosition")
312             this.setSliderXPosition(value);
313     },
314 
315     setOnPosition:function (onPosition) {
316         this._onPosition = onPosition;
317     },
318     getOnPosition:function () {
319         return this._onPosition;
320     },
321 
322     setOffPosition:function (offPosition) {
323         this._offPosition = offPosition;
324     },
325     getOffPosition:function () {
326         return this._offPosition;
327     },
328 
329     setMaskTexture:function (maskTexture) {
330         this._stencil.setTexture(maskTexture);
331     },
332     getMaskTexture:function () {
333         return this._stencil.getTexture();
334     },
335 
336     setTextureLocation:function (textureLocation) {
337         this._textureLocation = textureLocation;
338     },
339     getTextureLocation:function () {
340         return this._textureLocation;
341     },
342 
343     setMaskLocation:function (maskLocation) {
344         this._maskLocation = maskLocation;
345     },
346     getMaskLocation:function () {
347         return this._maskLocation;
348     },
349 
350     setOnSprite:function (onSprite) {
351         this._onSprite = onSprite;
352     },
353     getOnSprite:function () {
354         return this._onSprite;
355     },
356 
357     setOffSprite:function (offSprite) {
358         this._offSprite = offSprite;
359     },
360     getOffSprite:function () {
361         return this._offSprite;
362     },
363 
364     setThumbSprite:function (thumbSprite) {
365         this._thumbSprite = thumbSprite;
366     },
367     getThumbSprite:function () {
368         return this._thumbSprite;
369     },
370 
371     setOnLabel:function (onLabel) {
372         this._onLabel = onLabel;
373     },
374     getOnLabel:function () {
375         return this._onLabel;
376     },
377 
378     setOffLabel:function (offLabel) {
379         this._offLabel = offLabel;
380     },
381     getOffLabel:function () {
382         return this._offLabel;
383     }
384 });
385 
386 var _p = cc.ControlSwitchSprite.prototype;
387 
388 /** @expose */
389 _p.sliderX;
390 cc.defineGetterSetter(_p, "sliderX", _p.getSliderXPosition, _p.setSliderXPosition);
391 /** @expose */
392 _p.onPos;
393 cc.defineGetterSetter(_p, "onPos", _p.getOnPosition, _p.setOnPosition);
394 /** @expose */
395 _p.offPos;
396 cc.defineGetterSetter(_p, "offPos", _p.getOffPosition, _p.setOffPosition);
397 /** @expose */
398 _p.maskTexture;
399 cc.defineGetterSetter(_p, "maskTexture", _p.getMaskTexture, _p.setMaskTexture);
400 /** @expose */
401 _p.maskPos;
402 cc.defineGetterSetter(_p, "maskPos", _p.getMaskLocation, _p.setMaskLocation);
403 /** @expose */
404 _p.onSprite;
405 cc.defineGetterSetter(_p, "onSprite", _p.getOnSprite, _p.setOnSprite);
406 /** @expose */
407 _p.offSprite;
408 cc.defineGetterSetter(_p, "offSprite", _p.getOffSprite, _p.setOffSprite);
409 /** @expose */
410 _p.thumbSprite;
411 cc.defineGetterSetter(_p, "thumbSprite", _p.getThumbSprite, _p.setThumbSprite);
412 /** @expose */
413 _p.onLabel;
414 cc.defineGetterSetter(_p, "onLabel", _p.getOnLabel, _p.setOnLabel);
415 /** @expose */
416 _p.offLabel;
417 cc.defineGetterSetter(_p, "offLabel", _p.getOffLabel, _p.setOffLabel);
418 /** @expose */
419 _p.onSideWidth;
420 cc.defineGetterSetter(_p, "onSideWidth", _p._getOnSideWidth);
421 /** @expose */
422 _p.offSideWidth;
423 cc.defineGetterSetter(_p, "offSideWidth", _p._getOffSideWidth);
424 
425 _p = null;
426