CCScrollView.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /****************************************************************************
  2. Copyright (c) 2012 cocos2d-x.org
  3. Copyright (c) 2010 Sangwoo Im
  4. http://www.cocos2d-x.org
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in
  12. all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. THE SOFTWARE.
  20. ****************************************************************************/
  21. #include "CCScrollView.h"
  22. #include "platform/CCDevice.h"
  23. #include "2d/CCActionInstant.h"
  24. #include "2d/CCActionInterval.h"
  25. #include "2d/CCActionTween.h"
  26. #include "base/CCDirector.h"
  27. #include "base/CCEventDispatcher.h"
  28. #include "renderer/CCRenderer.h"
  29. #include <algorithm>
  30. NS_CC_EXT_BEGIN
  31. #define SCROLL_DEACCEL_RATE 0.95f
  32. #define SCROLL_DEACCEL_DIST 1.0f
  33. #define BOUNCE_DURATION 0.15f
  34. #define INSET_RATIO 0.2f
  35. #define MOVE_INCH 7.0f/160.0f
  36. #define BOUNCE_BACK_FACTOR 0.35f
  37. static float convertDistanceFromPointToInch(float pointDis)
  38. {
  39. auto glview = Director::getInstance()->getOpenGLView();
  40. float factor = ( glview->getScaleX() + glview->getScaleY() ) / 2;
  41. return pointDis * factor / Device::getDPI();
  42. }
  43. ScrollView::ScrollView()
  44. : _delegate(nullptr)
  45. , _direction(Direction::BOTH)
  46. , _dragging(false)
  47. , _container(nullptr)
  48. , _touchMoved(false)
  49. , _bounceable(false)
  50. , _clippingToBounds(false)
  51. , _touchLength(0.0f)
  52. , _minScale(0.0f)
  53. , _maxScale(0.0f)
  54. , _scissorRestored(false)
  55. , _touchListener(nullptr)
  56. , _animatedScrollAction(nullptr)
  57. ,_mapMinOffest(-1)
  58. ,_mapMaxOffest(-1)
  59. {
  60. }
  61. ScrollView::~ScrollView()
  62. {
  63. }
  64. ScrollView* ScrollView::create(Size size, Node* container/* = nullptr*/)
  65. {
  66. ScrollView* pRet = new (std::nothrow) ScrollView();
  67. if (pRet && pRet->initWithViewSize(size, container))
  68. {
  69. pRet->autorelease();
  70. }
  71. else
  72. {
  73. CC_SAFE_DELETE(pRet);
  74. }
  75. return pRet;
  76. }
  77. ScrollView* ScrollView::create()
  78. {
  79. ScrollView* pRet = new (std::nothrow) ScrollView();
  80. if (pRet && pRet->init())
  81. {
  82. pRet->autorelease();
  83. }
  84. else
  85. {
  86. CC_SAFE_DELETE(pRet);
  87. }
  88. return pRet;
  89. }
  90. bool ScrollView::initWithViewSize(Size size, Node *container/* = nullptr*/)
  91. {
  92. if (Layer::init())
  93. {
  94. _container = container;
  95. if (!this->_container)
  96. {
  97. _container = Layer::create();
  98. _container->setIgnoreAnchorPointForPosition(false);
  99. _container->setAnchorPoint(Vec2(0.0f, 0.0f));
  100. }
  101. this->setViewSize(size);
  102. setTouchEnabled(true);
  103. _touches.reserve(EventTouch::MAX_TOUCHES);
  104. _delegate = nullptr;
  105. _bounceable = true;
  106. _clippingToBounds = true;
  107. //_container->setContentSize(Size::ZERO);
  108. _direction = Direction::BOTH;
  109. _container->setPosition(0.0f, 0.0f);
  110. _touchLength = 0.0f;
  111. this->addChild(_container);
  112. _minScale = _maxScale = 1.0f;
  113. return true;
  114. }
  115. return false;
  116. }
  117. bool ScrollView::init()
  118. {
  119. return this->initWithViewSize(Size(200, 200), nullptr);
  120. }
  121. bool ScrollView::isNodeVisible(Node* node)
  122. {
  123. const Vec2 offset = this->getContentOffset();
  124. const Size size = this->getViewSize();
  125. const float scale = this->getZoomScale();
  126. Rect viewRect;
  127. viewRect = Rect(-offset.x/scale, -offset.y/scale, size.width/scale, size.height/scale);
  128. return viewRect.intersectsRect(node->getBoundingBox());
  129. }
  130. void ScrollView::pause(Ref* /*sender*/)
  131. {
  132. _container->pause();
  133. auto& children = _container->getChildren();
  134. for(const auto &child : children) {
  135. child->pause();
  136. }
  137. }
  138. void ScrollView::resume(Ref* /*sender*/)
  139. {
  140. auto& children = _container->getChildren();
  141. for(const auto &child : children) {
  142. child->resume();
  143. }
  144. _container->resume();
  145. }
  146. bool ScrollView::isTouchEnabled() const
  147. {
  148. return _touchListener != nullptr;
  149. }
  150. void ScrollView::setTouchEnabled(bool enabled)
  151. {
  152. _eventDispatcher->removeEventListener(_touchListener);
  153. _touchListener = nullptr;
  154. if (enabled)
  155. {
  156. _touchListener = EventListenerTouchOneByOne::create();
  157. _touchListener->setSwallowTouches(true);
  158. _touchListener->onTouchBegan = CC_CALLBACK_2(ScrollView::onTouchBegan, this);
  159. _touchListener->onTouchMoved = CC_CALLBACK_2(ScrollView::onTouchMoved, this);
  160. _touchListener->onTouchEnded = CC_CALLBACK_2(ScrollView::onTouchEnded, this);
  161. _touchListener->onTouchCancelled = CC_CALLBACK_2(ScrollView::onTouchCancelled, this);
  162. _eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
  163. }
  164. else
  165. {
  166. _dragging = false;
  167. _touchMoved = false;
  168. _touches.clear();
  169. }
  170. }
  171. void ScrollView::setSwallowTouches(bool needSwallow)
  172. {
  173. if (_touchListener != nullptr)
  174. {
  175. _touchListener->setSwallowTouches(needSwallow);
  176. }
  177. }
  178. void ScrollView::setContentOffset(Vec2 offset, bool animated/* = false*/)
  179. {
  180. // add song
  181. if(_bounceable && checkIsCanMove(offset))return;
  182. if (animated)
  183. { //animate scrolling
  184. this->setContentOffsetInDuration(offset, BOUNCE_DURATION);
  185. }
  186. else
  187. { //set the container position directly
  188. if (!_bounceable)
  189. {
  190. const Vec2 minOffset = this->minContainerOffset();
  191. const Vec2 maxOffset = this->maxContainerOffset();
  192. offset.x = MAX(minOffset.x, MIN(maxOffset.x, offset.x));
  193. offset.y = MAX(minOffset.y, MIN(maxOffset.y, offset.y));
  194. }
  195. _container->setPosition(offset);
  196. if (_delegate != nullptr)
  197. {
  198. _delegate->scrollViewDidScroll(this);
  199. }
  200. }
  201. }
  202. void ScrollView::setContentOffsetInDuration(Vec2 offset, float dt)
  203. {
  204. FiniteTimeAction *scroll, *expire;
  205. if (_animatedScrollAction) {
  206. stopAnimatedContentOffset();
  207. }
  208. scroll = MoveTo::create(dt, offset);
  209. expire = CallFuncN::create(CC_CALLBACK_1(ScrollView::stoppedAnimatedScroll,this));
  210. _animatedScrollAction = _container->runAction(Sequence::create(scroll, expire, nullptr));
  211. _animatedScrollAction->retain();
  212. this->schedule(CC_SCHEDULE_SELECTOR(ScrollView::performedAnimatedScroll));
  213. }
  214. void ScrollView::stopAnimatedContentOffset() {
  215. stopAction(_animatedScrollAction);
  216. _animatedScrollAction->release();
  217. _animatedScrollAction = nullptr;
  218. stoppedAnimatedScroll(this);
  219. }
  220. Vec2 ScrollView::getContentOffset()
  221. {
  222. return _container->getPosition();
  223. }
  224. void ScrollView::setZoomScale(float s)
  225. {
  226. if (_container->getScale() != s)
  227. {
  228. Vec2 oldCenter, newCenter;
  229. Vec2 center;
  230. if (_touchLength == 0.0f)
  231. {
  232. center.set(_viewSize.width*0.5f, _viewSize.height*0.5f);
  233. center = this->convertToWorldSpace(center);
  234. }
  235. else
  236. {
  237. center = _touchPoint;
  238. }
  239. oldCenter = _container->convertToNodeSpace(center);
  240. _container->setScale(MAX(_minScale, MIN(_maxScale, s)));
  241. newCenter = _container->convertToWorldSpace(oldCenter);
  242. const Vec2 offset = center - newCenter;
  243. if (_delegate != nullptr)
  244. {
  245. _delegate->scrollViewDidZoom(this);
  246. }
  247. this->setContentOffset(_container->getPosition() + offset);
  248. }
  249. }
  250. float ScrollView::getZoomScale()
  251. {
  252. return _container->getScale();
  253. }
  254. void ScrollView::setZoomScale(float s, bool animated)
  255. {
  256. if (animated)
  257. {
  258. this->setZoomScaleInDuration(s, BOUNCE_DURATION);
  259. }
  260. else
  261. {
  262. this->setZoomScale(s);
  263. }
  264. }
  265. void ScrollView::setZoomScaleInDuration(float s, float dt)
  266. {
  267. if (dt > 0)
  268. {
  269. if (_container->getScale() != s)
  270. {
  271. ActionTween *scaleAction;
  272. scaleAction = ActionTween::create(dt, "zoomScale", _container->getScale(), s);
  273. this->runAction(scaleAction);
  274. }
  275. }
  276. else
  277. {
  278. this->setZoomScale(s);
  279. }
  280. }
  281. void ScrollView::updateTweenAction(float value, const std::string& /*key*/)
  282. {
  283. this->setZoomScale(value);
  284. }
  285. void ScrollView::setViewSize(Size size)
  286. {
  287. _viewSize = size;
  288. Layer::setContentSize(size);
  289. }
  290. Node * ScrollView::getContainer()
  291. {
  292. return this->_container;
  293. }
  294. void ScrollView::setContainer(Node * pContainer)
  295. {
  296. // Make sure that '_container' has a non-nullptr value since there are
  297. // lots of logic that use '_container'.
  298. if (nullptr == pContainer)
  299. return;
  300. this->removeAllChildrenWithCleanup(true);
  301. this->_container = pContainer;
  302. this->_container->setIgnoreAnchorPointForPosition(false);
  303. this->_container->setAnchorPoint(Vec2(0.0f, 0.0f));
  304. this->addChild(this->_container);
  305. this->setViewSize(this->_viewSize);
  306. }
  307. bool ScrollView::hasVisibleParents() const
  308. {
  309. auto parent = this->getParent();
  310. for( auto c = parent; c != nullptr; c = c->getParent() )
  311. {
  312. if( !c->isVisible() )
  313. {
  314. return false;
  315. }
  316. }
  317. return true;
  318. }
  319. //add song
  320. void ScrollView::setMapMinOffset(float distance){
  321. _mapMinOffest = distance;
  322. }
  323. void ScrollView::setMapMaxOffset(float distance){
  324. _mapMaxOffest = distance;
  325. }
  326. bool ScrollView::checkIsCanMove(Vec2 offset){
  327. if(_mapMaxOffest == -1 && _mapMinOffest == -1)return false;
  328. if(_direction == Direction::HORIZONTAL){
  329. if((_mapMinOffest!=-1 && offset.x >_mapMinOffest) || ( _mapMaxOffest!=-1 && offset.x < _viewSize.width - _container->getContentSize().width - _mapMaxOffest)){
  330. return true;
  331. }
  332. }else if (_direction == Direction::VERTICAL){
  333. if((_mapMinOffest!=-1 && offset.y >_mapMinOffest) || ( _mapMaxOffest!=-1 && offset.y < _viewSize.height - _container->getContentSize().height - _mapMaxOffest)){
  334. return true;
  335. }
  336. }else{
  337. CCASSERT(false,"不支持!!!");
  338. }
  339. return false;
  340. }
  341. void ScrollView::relocateContainer(bool animated)
  342. {
  343. Vec2 oldPoint, min, max;
  344. float newX, newY;
  345. min = this->minContainerOffset();
  346. max = this->maxContainerOffset();
  347. oldPoint = _container->getPosition();
  348. newX = oldPoint.x;
  349. newY = oldPoint.y;
  350. if (_direction == Direction::BOTH || _direction == Direction::HORIZONTAL)
  351. {
  352. newX = MAX(newX, min.x);
  353. newX = MIN(newX, max.x);
  354. }
  355. if (_direction == Direction::BOTH || _direction == Direction::VERTICAL)
  356. {
  357. newY = MIN(newY, max.y);
  358. newY = MAX(newY, min.y);
  359. }
  360. if (newY != oldPoint.y || newX != oldPoint.x)
  361. {
  362. this->setContentOffset(Vec2(newX, newY), animated);
  363. }
  364. }
  365. Vec2 ScrollView::maxContainerOffset()
  366. {
  367. Point anchorPoint = _container->isIgnoreAnchorPointForPosition()?Point::ZERO:_container->getAnchorPoint();
  368. float contW = _container->getContentSize().width * _container->getScaleX();
  369. float contH = _container->getContentSize().height * _container->getScaleY();
  370. return Vec2(anchorPoint.x * contW, anchorPoint.y * contH);
  371. }
  372. Vec2 ScrollView::minContainerOffset()
  373. {
  374. Point anchorPoint = _container->isIgnoreAnchorPointForPosition()?Point::ZERO:_container->getAnchorPoint();
  375. float contW = _container->getContentSize().width * _container->getScaleX();
  376. float contH = _container->getContentSize().height * _container->getScaleY();
  377. return Vec2(_viewSize.width - (1 - anchorPoint.x) * contW, _viewSize.height - (1 - anchorPoint.y) * contH);
  378. }
  379. void ScrollView::deaccelerateScrolling(float /*dt*/)
  380. {
  381. // add song
  382. Vec2 offset = (_container->getPosition()+_scrollDistance);
  383. if(_bounceable && checkIsCanMove(offset)){
  384. this->unschedule(schedule_selector(ScrollView::deaccelerateScrolling));
  385. this->relocateContainer(true);
  386. return;
  387. }
  388. if (_dragging)
  389. {
  390. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollView::deaccelerateScrolling));
  391. return;
  392. }
  393. float newX, newY;
  394. Vec2 maxInset, minInset;
  395. _container->setPosition(_container->getPosition() + _scrollDistance);
  396. if (_bounceable)
  397. {
  398. maxInset = _maxInset;
  399. minInset = _minInset;
  400. }
  401. else
  402. {
  403. maxInset = this->maxContainerOffset();
  404. minInset = this->minContainerOffset();
  405. }
  406. newX = _container->getPosition().x;
  407. newY = _container->getPosition().y;
  408. _scrollDistance = _scrollDistance * SCROLL_DEACCEL_RATE;
  409. this->setContentOffset(Vec2(newX,newY));
  410. if ((fabsf(_scrollDistance.x) <= SCROLL_DEACCEL_DIST &&
  411. fabsf(_scrollDistance.y) <= SCROLL_DEACCEL_DIST) ||
  412. ((_direction == Direction::BOTH || _direction == Direction::VERTICAL) && (newY >= maxInset.y || newY <= minInset.y)) ||
  413. ((_direction == Direction::BOTH || _direction == Direction::HORIZONTAL) && (newX >= maxInset.x || newX <= minInset.x)))
  414. {
  415. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollView::deaccelerateScrolling));
  416. this->relocateContainer(true);
  417. }
  418. }
  419. void ScrollView::stoppedAnimatedScroll(Node * /*node*/)
  420. {
  421. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollView::performedAnimatedScroll));
  422. // After the animation stopped, "scrollViewDidScroll" should be invoked, this could fix the bug of lack of tableview cells.
  423. if (_delegate != nullptr)
  424. {
  425. _delegate->scrollViewDidScroll(this);
  426. }
  427. }
  428. void ScrollView::performedAnimatedScroll(float /*dt*/)
  429. {
  430. if (_dragging)
  431. {
  432. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollView::performedAnimatedScroll));
  433. return;
  434. }
  435. if (_delegate != nullptr)
  436. {
  437. _delegate->scrollViewDidScroll(this);
  438. }
  439. }
  440. const Size& ScrollView::getContentSize() const
  441. {
  442. return _container->getContentSize();
  443. }
  444. void ScrollView::setContentSize(const Size & size)
  445. {
  446. if (this->getContainer() != nullptr)
  447. {
  448. this->getContainer()->setContentSize(size);
  449. this->updateInset();
  450. }
  451. }
  452. void ScrollView::updateInset()
  453. {
  454. if (this->getContainer() != nullptr)
  455. {
  456. _maxInset = this->maxContainerOffset();
  457. _maxInset.set(_maxInset.x + _viewSize.width * INSET_RATIO,
  458. _maxInset.y + _viewSize.height * INSET_RATIO);
  459. _minInset = this->minContainerOffset();
  460. _minInset.set(_minInset.x - _viewSize.width * INSET_RATIO,
  461. _minInset.y - _viewSize.height * INSET_RATIO);
  462. }
  463. }
  464. /**
  465. * make sure all children go to the container
  466. */
  467. void ScrollView::addChild(Node * child, int zOrder, int tag)
  468. {
  469. if (_container != child) {
  470. _container->addChild(child, zOrder, tag);
  471. } else {
  472. Layer::addChild(child, zOrder, tag);
  473. }
  474. }
  475. void ScrollView::removeChild(Node* node, bool cleanup)
  476. {
  477. if(_container != node)
  478. {
  479. _container->removeChild(node, cleanup);
  480. }
  481. else
  482. {
  483. Layer::removeChild(node, cleanup);
  484. }
  485. }
  486. void ScrollView::removeAllChildrenWithCleanup(bool cleanup)
  487. {
  488. _container->removeAllChildrenWithCleanup(cleanup);
  489. Layer::removeAllChildrenWithCleanup(cleanup);
  490. }
  491. void ScrollView::removeAllChildren()
  492. {
  493. removeAllChildrenWithCleanup(true);
  494. }
  495. void ScrollView::addChild(Node * child, int zOrder, const std::string &name)
  496. {
  497. if (_container != child)
  498. {
  499. _container->addChild(child, zOrder, name);
  500. }
  501. else
  502. {
  503. Layer::addChild(child, zOrder, name);
  504. }
  505. }
  506. void ScrollView::beforeDraw()
  507. {
  508. //ScrollView don't support drawing in 3D space
  509. _beforeDrawCommand.init(_globalZOrder);
  510. _beforeDrawCommand.func = CC_CALLBACK_0(ScrollView::onBeforeDraw, this);
  511. Director::getInstance()->getRenderer()->addCommand(&_beforeDrawCommand);
  512. }
  513. /**
  514. * clip this view so that outside of the visible bounds can be hidden.
  515. */
  516. void ScrollView::onBeforeDraw()
  517. {
  518. if (_clippingToBounds)
  519. {
  520. _scissorRestored = false;
  521. Rect frame = getViewRect();
  522. auto glview = Director::getInstance()->getOpenGLView();
  523. if (glview->getVR() == nullptr) {
  524. if (glview->isScissorEnabled()) {
  525. _scissorRestored = true;
  526. _parentScissorRect = glview->getScissorRect();
  527. //set the intersection of _parentScissorRect and frame as the new scissor rect
  528. if (frame.intersectsRect(_parentScissorRect)) {
  529. float x = MAX(frame.origin.x, _parentScissorRect.origin.x);
  530. float y = MAX(frame.origin.y, _parentScissorRect.origin.y);
  531. float xx = MIN(frame.origin.x + frame.size.width, _parentScissorRect.origin.x + _parentScissorRect.size.width);
  532. float yy = MIN(frame.origin.y + frame.size.height, _parentScissorRect.origin.y + _parentScissorRect.size.height);
  533. glview->setScissorInPoints(x, y, xx - x, yy - y);
  534. }
  535. }
  536. else {
  537. glEnable(GL_SCISSOR_TEST);
  538. glview->setScissorInPoints(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
  539. }
  540. }
  541. }
  542. }
  543. void ScrollView::afterDraw()
  544. {
  545. _afterDrawCommand.init(_globalZOrder);
  546. _afterDrawCommand.func = CC_CALLBACK_0(ScrollView::onAfterDraw, this);
  547. Director::getInstance()->getRenderer()->addCommand(&_afterDrawCommand);
  548. }
  549. /**
  550. * retract what's done in beforeDraw so that there's no side effect to
  551. * other nodes.
  552. */
  553. void ScrollView::onAfterDraw()
  554. {
  555. if (_clippingToBounds)
  556. {
  557. auto glview = Director::getInstance()->getOpenGLView();
  558. if (glview->getVR() == nullptr) {
  559. if (_scissorRestored) {//restore the parent's scissor rect
  560. glview->setScissorInPoints(_parentScissorRect.origin.x, _parentScissorRect.origin.y, _parentScissorRect.size.width, _parentScissorRect.size.height);
  561. }
  562. else {
  563. glDisable(GL_SCISSOR_TEST);
  564. }
  565. }
  566. }
  567. }
  568. void ScrollView::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)
  569. {
  570. // quick return if not visible
  571. if (!isVisible())
  572. {
  573. return;
  574. }
  575. uint32_t flags = processParentFlags(parentTransform, parentFlags);
  576. // IMPORTANT:
  577. // To ease the migration to v3.0, we still support the Mat4 stack,
  578. // but it is deprecated and your code should not rely on it
  579. Director* director = Director::getInstance();
  580. CCASSERT(nullptr != director, "Director is null when setting matrix stack");
  581. director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  582. director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
  583. this->beforeDraw();
  584. bool visibleByCamera = isVisitableByVisitingCamera();
  585. if (!_children.empty())
  586. {
  587. int i=0;
  588. // draw children zOrder < 0
  589. for( ; i < _children.size(); i++ )
  590. {
  591. Node *child = _children.at(i);
  592. if ( child->getLocalZOrder() < 0 )
  593. {
  594. child->visit(renderer, _modelViewTransform, flags);
  595. }
  596. else
  597. {
  598. break;
  599. }
  600. }
  601. // this draw
  602. if (visibleByCamera)
  603. this->draw(renderer, _modelViewTransform, flags);
  604. // draw children zOrder >= 0
  605. for( ; i < _children.size(); i++ )
  606. {
  607. Node *child = _children.at(i);
  608. child->visit(renderer, _modelViewTransform, flags);
  609. }
  610. }
  611. else if (visibleByCamera)
  612. {
  613. this->draw(renderer, _modelViewTransform, flags);
  614. }
  615. this->afterDraw();
  616. director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  617. }
  618. bool ScrollView::onTouchBegan(Touch* touch, Event* /*event*/)
  619. {
  620. if (!this->isVisible() || !this->hasVisibleParents())
  621. {
  622. return false;
  623. }
  624. Rect frame = getViewRect();
  625. //dispatcher does not know about clipping. reject touches outside visible bounds.
  626. if (_touches.size() > 2 ||
  627. _touchMoved ||
  628. !frame.containsPoint(touch->getLocation()))
  629. {
  630. return false;
  631. }
  632. if (std::find(_touches.begin(), _touches.end(), touch) == _touches.end())
  633. {
  634. _touches.push_back(touch);
  635. }
  636. if (_touches.size() == 1)
  637. { // scrolling
  638. _touchPoint = this->convertTouchToNodeSpace(touch);
  639. _touchMoved = false;
  640. _dragging = true; //dragging started
  641. _scrollDistance.setZero();
  642. _touchLength = 0.0f;
  643. }
  644. else if (_touches.size() == 2)
  645. {
  646. _touchPoint = (this->convertTouchToNodeSpace(_touches[0]).getMidpoint(
  647. this->convertTouchToNodeSpace(_touches[1])));
  648. _touchLength = _container->convertTouchToNodeSpace(_touches[0]).getDistance(
  649. _container->convertTouchToNodeSpace(_touches[1]));
  650. _dragging = false;
  651. }
  652. return true;
  653. }
  654. void ScrollView::onTouchMoved(Touch* touch, Event* /*event*/)
  655. {
  656. if (!this->isVisible())
  657. {
  658. return;
  659. }
  660. if (std::find(_touches.begin(), _touches.end(), touch) != _touches.end())
  661. {
  662. if (_touches.size() == 1 && _dragging)
  663. { // scrolling
  664. Vec2 moveDistance, newPoint;
  665. Rect frame;
  666. float newX, newY;
  667. frame = getViewRect();
  668. newPoint = this->convertTouchToNodeSpace(_touches[0]);
  669. moveDistance = newPoint - _touchPoint;
  670. float dis = 0.0f;
  671. if (_direction == Direction::VERTICAL)
  672. {
  673. dis = moveDistance.y;
  674. float pos = _container->getPosition().y;
  675. if (!(minContainerOffset().y <= pos && pos <= maxContainerOffset().y)) {
  676. moveDistance.y *= BOUNCE_BACK_FACTOR;
  677. }
  678. }
  679. else if (_direction == Direction::HORIZONTAL)
  680. {
  681. dis = moveDistance.x;
  682. float pos = _container->getPosition().x;
  683. if (!(minContainerOffset().x <= pos && pos <= maxContainerOffset().x)) {
  684. moveDistance.x *= BOUNCE_BACK_FACTOR;
  685. }
  686. }
  687. else
  688. {
  689. dis = sqrtf(moveDistance.x*moveDistance.x + moveDistance.y*moveDistance.y);
  690. float pos = _container->getPosition().y;
  691. if (!(minContainerOffset().y <= pos && pos <= maxContainerOffset().y)) {
  692. moveDistance.y *= BOUNCE_BACK_FACTOR;
  693. }
  694. pos = _container->getPosition().x;
  695. if (!(minContainerOffset().x <= pos && pos <= maxContainerOffset().x)) {
  696. moveDistance.x *= BOUNCE_BACK_FACTOR;
  697. }
  698. }
  699. if (!_touchMoved && fabs(convertDistanceFromPointToInch(dis)) < MOVE_INCH )
  700. {
  701. //CCLOG("Invalid movement, distance = [%f, %f], disInch = %f", moveDistance.x, moveDistance.y);
  702. return;
  703. }
  704. if (!_touchMoved)
  705. {
  706. moveDistance.setZero();
  707. }
  708. _touchPoint = newPoint;
  709. _touchMoved = true;
  710. if (_dragging)
  711. {
  712. switch (_direction)
  713. {
  714. case Direction::VERTICAL:
  715. moveDistance.set(0.0f, moveDistance.y);
  716. break;
  717. case Direction::HORIZONTAL:
  718. moveDistance.set(moveDistance.x, 0.0f);
  719. break;
  720. default:
  721. break;
  722. }
  723. newX = _container->getPosition().x + moveDistance.x;
  724. newY = _container->getPosition().y + moveDistance.y;
  725. _scrollDistance = moveDistance;
  726. this->setContentOffset(Vec2(newX, newY));
  727. }
  728. }
  729. else if (_touches.size() == 2 && !_dragging)
  730. {
  731. const float len = _container->convertTouchToNodeSpace(_touches[0]).getDistance(
  732. _container->convertTouchToNodeSpace(_touches[1]));
  733. this->setZoomScale(this->getZoomScale()*len/_touchLength);
  734. }
  735. }
  736. }
  737. void ScrollView::onTouchEnded(Touch* touch, Event* /*event*/)
  738. {
  739. if (!this->isVisible())
  740. {
  741. return;
  742. }
  743. auto touchIter = std::find(_touches.begin(), _touches.end(), touch);
  744. if (touchIter != _touches.end())
  745. {
  746. if (_touches.size() == 1 && _touchMoved)
  747. {
  748. this->schedule(CC_SCHEDULE_SELECTOR(ScrollView::deaccelerateScrolling));
  749. }
  750. _touches.erase(touchIter);
  751. }
  752. if (_touches.size() == 0)
  753. {
  754. _dragging = false;
  755. _touchMoved = false;
  756. }
  757. }
  758. void ScrollView::onTouchCancelled(Touch* touch, Event* /*event*/)
  759. {
  760. if (!this->isVisible())
  761. {
  762. return;
  763. }
  764. auto touchIter = std::find(_touches.begin(), _touches.end(), touch);
  765. if ( touchIter == _touches.end() )
  766. return;
  767. _touches.erase(touchIter);
  768. if (_touches.size() == 0)
  769. {
  770. _dragging = false;
  771. _touchMoved = false;
  772. }
  773. }
  774. Rect ScrollView::getViewRect()
  775. {
  776. Vec2 screenPos = this->convertToWorldSpace(Vec2::ZERO);
  777. float scaleX = this->getScaleX();
  778. float scaleY = this->getScaleY();
  779. for (Node *p = _parent; p != nullptr; p = p->getParent()) {
  780. scaleX *= p->getScaleX();
  781. scaleY *= p->getScaleY();
  782. }
  783. // Support negative scaling. Not doing so causes intersectsRect calls
  784. // (eg: to check if the touch was within the bounds) to return false.
  785. // Note, Node::getScale will assert if X and Y scales are different.
  786. if(scaleX<0.f) {
  787. screenPos.x += _viewSize.width*scaleX;
  788. scaleX = -scaleX;
  789. }
  790. if(scaleY<0.f) {
  791. screenPos.y += _viewSize.height*scaleY;
  792. scaleY = -scaleY;
  793. }
  794. return Rect(screenPos.x, screenPos.y, _viewSize.width*scaleX, _viewSize.height*scaleY);
  795. }
  796. NS_CC_EXT_END