CCControlSwitch.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. #include "CCControlSwitch.h"
  28. #include "2d/CCSprite.h"
  29. #include "2d/CCActionTween.h"
  30. #include "2d/CCLabel.h"
  31. #include "2d/CCClippingNode.h"
  32. #include "renderer/ccShaders.h"
  33. #include "2d/CCRenderTexture.h"
  34. NS_CC_EXT_BEGIN
  35. // ControlSwitchSprite
  36. class ControlSwitchSprite : public Sprite, public ActionTweenDelegate
  37. {
  38. public:
  39. /** creates an autorelease instance of ControlSwitchSprite */
  40. static ControlSwitchSprite* create(
  41. Sprite *maskSprite,
  42. Sprite *onSprite,
  43. Sprite *offSprite,
  44. Sprite *thumbSprite,
  45. Label* onLabel,
  46. Label* offLabel);
  47. /**
  48. * @js NA
  49. * @lua NA
  50. */
  51. void needsLayout();
  52. /**
  53. * @js NA
  54. * @lua NA
  55. */
  56. void setSliderXPosition(float sliderXPosition);
  57. /**
  58. * @js NA
  59. * @lua NA
  60. */
  61. float getSliderXPosition() {return _sliderXPosition;}
  62. /**
  63. * @js NA
  64. * @lua NA
  65. */
  66. float onSideWidth();
  67. /**
  68. * @js NA
  69. * @lua NA
  70. */
  71. float offSideWidth();
  72. /**
  73. * @js NA
  74. * @lua NA
  75. */
  76. virtual void updateTweenAction(float value, const std::string& key) override;
  77. /** Contains the position (in x-axis) of the slider inside the receiver. */
  78. float _sliderXPosition;
  79. CC_SYNTHESIZE(float, _onPosition, OnPosition)
  80. CC_SYNTHESIZE(float, _offPosition, OffPosition)
  81. CC_SYNTHESIZE_RETAIN(Texture2D*, _maskTexture, MaskTexture)
  82. CC_SYNTHESIZE(GLuint, _textureLocation, TextureLocation)
  83. CC_SYNTHESIZE(GLuint, _maskLocation, MaskLocation)
  84. CC_SYNTHESIZE_RETAIN(Sprite*, _onSprite, OnSprite)
  85. CC_SYNTHESIZE_RETAIN(Sprite*, _offSprite, OffSprite)
  86. CC_SYNTHESIZE_RETAIN(Sprite*, _thumbSprite, ThumbSprite)
  87. CC_SYNTHESIZE_RETAIN(Label*, _onLabel, OnLabel)
  88. CC_SYNTHESIZE_RETAIN(Label*, _offLabel, OffLabel)
  89. Sprite* _clipperStencil;
  90. protected:
  91. /**
  92. * @js NA
  93. * @lua NA
  94. */
  95. ControlSwitchSprite();
  96. /**
  97. * @js NA
  98. * @lua NA
  99. */
  100. virtual ~ControlSwitchSprite();
  101. /**
  102. * @js NA
  103. * @lua NA
  104. */
  105. bool initWithMaskSprite(
  106. Sprite *maskSprite,
  107. Sprite *onSprite,
  108. Sprite *offSprite,
  109. Sprite *thumbSprite,
  110. Label* onLabel,
  111. Label* offLabel);
  112. private:
  113. CC_DISALLOW_COPY_AND_ASSIGN(ControlSwitchSprite);
  114. };
  115. ControlSwitchSprite* ControlSwitchSprite::create(Sprite *maskSprite,
  116. Sprite *onSprite,
  117. Sprite *offSprite,
  118. Sprite *thumbSprite,
  119. Label* onLabel,
  120. Label* offLabel)
  121. {
  122. auto ret = new (std::nothrow) ControlSwitchSprite();
  123. ret->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel);
  124. ret->autorelease();
  125. return ret;
  126. }
  127. ControlSwitchSprite::ControlSwitchSprite()
  128. : _sliderXPosition(0.0f)
  129. , _onPosition(0.0f)
  130. , _offPosition(0.0f)
  131. , _maskTexture(nullptr)
  132. , _textureLocation(0)
  133. , _maskLocation(0)
  134. , _onSprite(nullptr)
  135. , _offSprite(nullptr)
  136. , _thumbSprite(nullptr)
  137. , _onLabel(nullptr)
  138. , _offLabel(nullptr)
  139. , _clipperStencil(nullptr)
  140. {
  141. }
  142. ControlSwitchSprite::~ControlSwitchSprite()
  143. {
  144. CC_SAFE_RELEASE(_onSprite);
  145. CC_SAFE_RELEASE(_offSprite);
  146. CC_SAFE_RELEASE(_thumbSprite);
  147. CC_SAFE_RELEASE(_onLabel);
  148. CC_SAFE_RELEASE(_offLabel);
  149. CC_SAFE_RELEASE(_maskTexture);
  150. CC_SAFE_RELEASE(_clipperStencil);
  151. }
  152. bool ControlSwitchSprite::initWithMaskSprite(
  153. Sprite *maskSprite,
  154. Sprite *onSprite,
  155. Sprite *offSprite,
  156. Sprite *thumbSprite,
  157. Label* onLabel,
  158. Label* offLabel)
  159. {
  160. if (Sprite::initWithTexture(maskSprite->getTexture()))
  161. {
  162. // Sets the default values
  163. _onPosition = 0;
  164. _offPosition = -onSprite->getContentSize().width + thumbSprite->getContentSize().width / 2;
  165. _sliderXPosition = _onPosition;
  166. setOnSprite(onSprite);
  167. setOffSprite(offSprite);
  168. setThumbSprite(thumbSprite);
  169. setOnLabel(onLabel);
  170. setOffLabel(offLabel);
  171. ClippingNode* clipper = ClippingNode::create();
  172. _clipperStencil = Sprite::createWithTexture(maskSprite->getTexture());
  173. _clipperStencil->retain();
  174. clipper->setAlphaThreshold(0.1f);
  175. clipper->setStencil(_clipperStencil);
  176. clipper->addChild(onSprite);
  177. clipper->addChild(offSprite);
  178. if (onLabel) {
  179. clipper->addChild(onLabel); // might be null
  180. }
  181. if (offLabel) {
  182. clipper->addChild(offLabel); // might be null
  183. }
  184. clipper->addChild(thumbSprite);
  185. addChild(clipper);
  186. // Set up the mask with the Mask shader
  187. setMaskTexture(maskSprite->getTexture());
  188. setContentSize(_maskTexture->getContentSize());
  189. needsLayout();
  190. return true;
  191. }
  192. return false;
  193. }
  194. void ControlSwitchSprite::updateTweenAction(float value, const std::string& key)
  195. {
  196. CCLOGINFO("key = %s, value = %f", key.c_str(), value);
  197. setSliderXPosition(value);
  198. }
  199. void ControlSwitchSprite::needsLayout()
  200. {
  201. _onSprite->setPosition(_onSprite->getContentSize().width / 2 + _sliderXPosition,
  202. _onSprite->getContentSize().height / 2);
  203. _offSprite->setPosition(_onSprite->getContentSize().width + _offSprite->getContentSize().width / 2 + _sliderXPosition,
  204. _offSprite->getContentSize().height / 2);
  205. _thumbSprite->setPosition(_onSprite->getContentSize().width + _sliderXPosition,
  206. _maskTexture->getContentSize().height / 2);
  207. _clipperStencil->setPosition(_maskTexture->getContentSize().width/2,
  208. _maskTexture->getContentSize().height / 2);
  209. if (_onLabel)
  210. {
  211. _onLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  212. _onLabel->setPosition(_onSprite->getPosition().x - _thumbSprite->getContentSize().width / 6,
  213. _onSprite->getContentSize().height / 2);
  214. }
  215. if (_offLabel)
  216. {
  217. _offLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  218. _offLabel->setPosition(_offSprite->getPosition().x + _thumbSprite->getContentSize().width / 6,
  219. _offSprite->getContentSize().height / 2);
  220. }
  221. setFlippedY(true);
  222. }
  223. void ControlSwitchSprite::setSliderXPosition(float sliderXPosition)
  224. {
  225. if (sliderXPosition <= _offPosition)
  226. {
  227. // Off
  228. sliderXPosition = _offPosition;
  229. } else if (sliderXPosition >= _onPosition)
  230. {
  231. // On
  232. sliderXPosition = _onPosition;
  233. }
  234. _sliderXPosition = sliderXPosition;
  235. needsLayout();
  236. }
  237. float ControlSwitchSprite::onSideWidth()
  238. {
  239. return _onSprite->getContentSize().width;
  240. }
  241. float ControlSwitchSprite::offSideWidth()
  242. {
  243. return _offSprite->getContentSize().height;
  244. }
  245. // ControlSwitch
  246. ControlSwitch::ControlSwitch()
  247. : _switchSprite(nullptr)
  248. , _initialTouchXPosition(0.0f)
  249. , _moved(false)
  250. , _on(false)
  251. {
  252. }
  253. ControlSwitch::~ControlSwitch()
  254. {
  255. CC_SAFE_RELEASE(_switchSprite);
  256. }
  257. bool ControlSwitch::initWithMaskSprite(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite)
  258. {
  259. return initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, nullptr, nullptr);
  260. }
  261. ControlSwitch* ControlSwitch::create(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite)
  262. {
  263. ControlSwitch* pRet = new (std::nothrow) ControlSwitch();
  264. if (pRet && pRet->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, nullptr, nullptr))
  265. {
  266. pRet->autorelease();
  267. }
  268. else
  269. {
  270. CC_SAFE_DELETE(pRet);
  271. }
  272. return pRet;
  273. }
  274. bool ControlSwitch::initWithMaskSprite(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite, Label* onLabel, Label* offLabel)
  275. {
  276. if (Control::init())
  277. {
  278. CCASSERT(maskSprite, "Mask must not be nil.");
  279. CCASSERT(onSprite, "onSprite must not be nil.");
  280. CCASSERT(offSprite, "offSprite must not be nil.");
  281. CCASSERT(thumbSprite, "thumbSprite must not be nil.");
  282. _on = true;
  283. _switchSprite = ControlSwitchSprite::create(maskSprite,
  284. onSprite,
  285. offSprite,
  286. thumbSprite,
  287. onLabel,
  288. offLabel);
  289. _switchSprite->retain();
  290. _switchSprite->setPosition(_switchSprite->getContentSize().width / 2, _switchSprite->getContentSize().height / 2);
  291. addChild(_switchSprite);
  292. setIgnoreAnchorPointForPosition(false);
  293. setAnchorPoint(Vec2(0.5f, 0.5f));
  294. setContentSize(_switchSprite->getContentSize());
  295. return true;
  296. }
  297. return false;
  298. }
  299. ControlSwitch* ControlSwitch::create(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite, Label* onLabel, Label* offLabel)
  300. {
  301. ControlSwitch* pRet = new (std::nothrow) ControlSwitch();
  302. if (pRet && pRet->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel))
  303. {
  304. pRet->autorelease();
  305. }
  306. else
  307. {
  308. CC_SAFE_DELETE(pRet);
  309. }
  310. return pRet;
  311. }
  312. void ControlSwitch::setOn(bool isOn)
  313. {
  314. setOn(isOn, false);
  315. }
  316. void ControlSwitch::setOn(bool isOn, bool animated)
  317. {
  318. _on = isOn;
  319. if (animated) {
  320. _switchSprite->runAction
  321. (
  322. ActionTween::create
  323. (
  324. 0.2f,
  325. "sliderXPosition",
  326. _switchSprite->getSliderXPosition(),
  327. (_on) ? _switchSprite->getOnPosition() : _switchSprite->getOffPosition()
  328. )
  329. );
  330. }
  331. else {
  332. _switchSprite->setSliderXPosition((_on) ? _switchSprite->getOnPosition() : _switchSprite->getOffPosition());
  333. }
  334. sendActionsForControlEvents(Control::EventType::VALUE_CHANGED);
  335. }
  336. void ControlSwitch::setEnabled(bool enabled)
  337. {
  338. _enabled = enabled;
  339. if (_switchSprite != nullptr)
  340. {
  341. _switchSprite->setOpacity((enabled) ? 255 : 128);
  342. }
  343. }
  344. Vec2 ControlSwitch::locationFromTouch(Touch* pTouch)
  345. {
  346. Vec2 touchLocation = pTouch->getLocation(); // Get the touch position
  347. touchLocation = this->convertToNodeSpace(touchLocation); // Convert to the node space of this class
  348. return touchLocation;
  349. }
  350. bool ControlSwitch::onTouchBegan(Touch *pTouch, Event* /*pEvent*/)
  351. {
  352. if (!isTouchInside(pTouch) || !isEnabled() || !isVisible())
  353. {
  354. return false;
  355. }
  356. _moved = false;
  357. Vec2 location = this->locationFromTouch(pTouch);
  358. _initialTouchXPosition = location.x - _switchSprite->getSliderXPosition();
  359. _switchSprite->getThumbSprite()->setColor(Color3B::GRAY);
  360. _switchSprite->needsLayout();
  361. return true;
  362. }
  363. void ControlSwitch::onTouchMoved(Touch *pTouch, Event* /*pEvent*/)
  364. {
  365. Vec2 location = this->locationFromTouch(pTouch);
  366. location = Vec2(location.x - _initialTouchXPosition, 0);
  367. _moved = true;
  368. _switchSprite->setSliderXPosition(location.x);
  369. }
  370. void ControlSwitch::onTouchEnded(Touch *pTouch, Event* /*pEvent*/)
  371. {
  372. Vec2 location = this->locationFromTouch(pTouch);
  373. _switchSprite->getThumbSprite()->setColor(Color3B::WHITE);
  374. if (hasMoved())
  375. {
  376. setOn(!(location.x < _switchSprite->getContentSize().width / 2), true);
  377. }
  378. else
  379. {
  380. setOn(!_on, true);
  381. }
  382. }
  383. void ControlSwitch::onTouchCancelled(Touch *pTouch, Event* /*pEvent*/)
  384. {
  385. Vec2 location = this->locationFromTouch(pTouch);
  386. _switchSprite->getThumbSprite()->setColor(Color3B::WHITE);
  387. if (hasMoved())
  388. {
  389. setOn(!(location.x < _switchSprite->getContentSize().width / 2), true);
  390. } else
  391. {
  392. setOn(!_on, true);
  393. }
  394. }
  395. NS_CC_EXT_END