LCOV - code coverage report
Current view: top level - xenolith/renderer/material2d/layout - MaterialMultiViewLayout.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 308 0.0 %
Date: 2024-05-12 00:16:13 Functions: 0 50 0.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "MaterialMultiViewLayout.h"
      24             : #include "XL2dScrollController.h"
      25             : #include "XL2dActionAcceleratedMove.h"
      26             : #include "XLInputListener.h"
      27             : #include "XL2dScrollView.h"
      28             : #include "XLAction.h"
      29             : #include "XLActionEase.h"
      30             : 
      31             : namespace STAPPLER_VERSIONIZED stappler::xenolith::material2d {
      32             : 
      33           0 : bool MultiViewLayout::Generator::init() {
      34           0 :         if (!Component::init()) {
      35           0 :                 return false;
      36             :         }
      37             : 
      38           0 :         return true;
      39             : }
      40             : 
      41           0 : bool MultiViewLayout::Generator::init(size_t count, const IndexViewCallback &gen) {
      42           0 :         if (!Component::init()) {
      43           0 :                 return false;
      44             :         }
      45             : 
      46           0 :         _viewCount = count;
      47           0 :         _makeViewByIndex = gen;
      48             : 
      49           0 :         return true;
      50             : }
      51           0 : bool MultiViewLayout::Generator::init(const SequenceViewCallback &seq) {
      52           0 :         if (!Component::init()) {
      53           0 :                 return false;
      54             :         }
      55             : 
      56           0 :         _makeViewSeq = seq;
      57             : 
      58           0 :         return true;
      59             : }
      60             : 
      61           0 : bool MultiViewLayout::Generator::isViewLocked(ScrollView *, int64_t index) {
      62           0 :         return !_enabled;
      63             : }
      64             : 
      65           0 : Rc<ScrollView> MultiViewLayout::Generator::makeIndexView(int64_t viewIndex) {
      66           0 :         if (_makeViewSeq) {
      67           0 :                 return _makeViewSeq(nullptr, viewIndex, 0);
      68           0 :         } else if (viewIndex >= 0 && viewIndex < int64_t(_viewCount) && _makeViewByIndex) {
      69           0 :                 return _makeViewByIndex(viewIndex);
      70             :         }
      71           0 :         return nullptr;
      72             : }
      73             : 
      74           0 : Rc<ScrollView> MultiViewLayout::Generator::makeNextView(ScrollView *view, int64_t viewIndex) {
      75           0 :         if (!_enabled) {
      76           0 :                 return nullptr;
      77             :         }
      78           0 :         if (_makeViewSeq) {
      79           0 :                 return _makeViewSeq(view, viewIndex, 1);
      80           0 :         } else if (_makeViewByIndex) {
      81           0 :                 return _makeViewByIndex(viewIndex + 1);
      82             :         }
      83           0 :         return nullptr;
      84             : }
      85             : 
      86           0 : Rc<ScrollView> MultiViewLayout::Generator::makePrevView(ScrollView *view, int64_t viewIndex) {
      87           0 :         if (!_enabled) {
      88           0 :                 return nullptr;
      89             :         }
      90           0 :         if (_makeViewSeq) {
      91           0 :                 return _makeViewSeq(view, viewIndex, -1);
      92           0 :         } else if (_makeViewByIndex) {
      93           0 :                 return _makeViewByIndex(viewIndex - 1);
      94             :         }
      95           0 :         return nullptr;
      96             : }
      97             : 
      98           0 : bool MultiViewLayout::Generator::isInfinite() const {
      99           0 :         return _viewCount == maxOf<size_t>();
     100             : }
     101             : 
     102           0 : int64_t MultiViewLayout::Generator::getViewCount() const {
     103           0 :         return _viewCount;
     104             : }
     105             : 
     106           0 : void MultiViewLayout::Generator::setViewSelectedCallback(const ViewCallback &cb) {
     107           0 :         _viewSelectedCallback = cb;
     108           0 : }
     109             : 
     110           0 : void MultiViewLayout::Generator::setViewCreatedCallback(const ViewCallback &cb) {
     111           0 :         _viewCreatedCallback = cb;
     112           0 : }
     113             : 
     114           0 : void MultiViewLayout::Generator::setApplyViewCallback(const ViewCallback &cb) {
     115           0 :         _applyViewCallback = cb;
     116           0 : }
     117             : 
     118           0 : void MultiViewLayout::Generator::setApplyProgressCallback(const ProgressCallback &cb) {
     119           0 :         _applyProgressCallback = cb;
     120           0 : }
     121             : 
     122           0 : void MultiViewLayout::Generator::onViewSelected(ScrollView *current, int64_t id) {
     123           0 :         if (_viewSelectedCallback) {
     124           0 :                 _viewSelectedCallback(current, id);
     125             :         }
     126           0 : }
     127           0 : void MultiViewLayout::Generator::onViewCreated(ScrollView *current, int64_t id) {
     128           0 :         if (_viewCreatedCallback) {
     129           0 :                 _viewCreatedCallback(current, id);
     130             :         }
     131           0 : }
     132             : 
     133           0 : void MultiViewLayout::Generator::onApplyView(ScrollView *current, int64_t id) {
     134           0 :         if (_applyViewCallback) {
     135           0 :                 _applyViewCallback(current, id);
     136             :         }
     137           0 : }
     138           0 : void MultiViewLayout::Generator::onApplyProgress(ScrollView *current, ScrollView *n, float progress) {
     139           0 :         if (_applyProgressCallback) {
     140           0 :                 _applyProgressCallback(current, n, progress);
     141             :         }
     142           0 : }
     143             : 
     144           0 : MultiViewLayout *MultiViewLayout::Generator::getLayout() {
     145           0 :         return dynamic_cast<MultiViewLayout *>(_owner);
     146             : }
     147             : 
     148           0 : bool MultiViewLayout::init(Generator *gen) {
     149           0 :         if (!FlexibleLayout::init()) {
     150           0 :                 return false;
     151             :         }
     152             : 
     153           0 :         if (!gen) {
     154           0 :                 _generator = addComponent(Rc<Generator>::create());
     155             :         } else {
     156           0 :                 _generator = addComponent(Rc<Generator>(gen));
     157             :         }
     158             : 
     159           0 :         _swipeListener = addInputListener(Rc<InputListener>::create());
     160           0 :         _swipeListener->addSwipeRecognizer([this] (const GestureSwipe &s) -> bool {
     161           0 :                 if (s.event == GestureEvent::Began) {
     162           0 :                         if (beginSwipe(s.delta)) {
     163           0 :                                 _swipeListener->setExclusiveForTouch(s.getId());
     164           0 :                                 return true;
     165             :                         }
     166           0 :                         return false;
     167           0 :                 } else if (s.event == GestureEvent::Activated) {
     168           0 :                         return setSwipeProgress(s.delta / s.density);
     169             :                 } else {
     170           0 :                         return endSwipeProgress(s.delta / s.density, s.velocity / s.density);
     171             :                 }
     172             :                 return true;
     173             :         }, TapDistanceAllowed, true);
     174             : 
     175           0 :         return true;
     176             : }
     177             : 
     178           0 : void MultiViewLayout::onPush(SceneContent2d *l, bool replace) {
     179           0 :         FlexibleLayout::onPush(l, replace);
     180             : 
     181           0 :         if (!_currentView) {
     182           0 :                 if (auto view = makeInitialView()) {
     183           0 :                         _currentView = view;
     184           0 :                         _nextView = nullptr;
     185             : 
     186           0 :                         onViewSelected(_currentView, _currentViewIndex);
     187           0 :                         setBaseNode(_currentView, ZOrder(1));
     188           0 :                         applyView(_currentView);
     189           0 :                 }
     190             :         }
     191           0 : }
     192             : 
     193           0 : void MultiViewLayout::setGenerator(Generator *gen) {
     194           0 :         if (_generator) {
     195           0 :                 removeComponent(_generator);
     196             :         }
     197           0 :         addComponentItem(gen);
     198           0 :         _generator = gen;
     199           0 : }
     200             : 
     201           0 : MultiViewLayout::Generator *MultiViewLayout::getGenerator() const {
     202           0 :         return _generator;
     203             : }
     204             : 
     205           0 : int64_t MultiViewLayout::getCurrentIndex() const {
     206           0 :         return _currentViewIndex;
     207             : }
     208             : 
     209           0 : void MultiViewLayout::showNextView(float val) {
     210           0 :         setFlexibleLevelAnimated(1.0f, val);
     211           0 :         auto a = Rc<ActionProgress>::create(val, [this] (float time) {
     212           0 :                 _swipeProgress = _contentSize.width * time * -1.0f;
     213           0 :                 onSwipeProgress();
     214           0 :         }, [] () {
     215             : 
     216           0 :         }, [this] () {
     217           0 :                 endSwipeProgress(Vec2(0.0f, 0.0f), Vec2(0.0f, 0.0f));
     218           0 :         });
     219           0 :         runAction(Rc<EaseQuadraticActionInOut>::create(a), "ListAction"_tag);
     220           0 : }
     221             : 
     222           0 : void MultiViewLayout::showPrevView(float val) {
     223           0 :         setFlexibleLevelAnimated(1.0f, val);
     224           0 :         auto a = Rc<ActionProgress>::create(val, [this] (float time) {
     225           0 :                 _swipeProgress = _contentSize.width * time;
     226           0 :                 onSwipeProgress();
     227           0 :         }, [] () {
     228             : 
     229           0 :         }, [this] () {
     230           0 :                 endSwipeProgress(Vec2(0.0f, 0.0f), Vec2(0.0f, 0.0f));
     231           0 :         });
     232           0 :         runAction(Rc<EaseQuadraticActionInOut>::create(a), "ListAction"_tag);
     233           0 : }
     234             : 
     235           0 : void MultiViewLayout::showIndexView(int64_t idx, float val) {
     236           0 :         if (_currentViewIndex < idx) {
     237           0 :                 _currentViewIndex = idx - 1;
     238           0 :                 showNextView(val);
     239           0 :         } else if (_currentViewIndex > idx) {
     240           0 :                 _currentViewIndex = idx + 1;
     241           0 :                 showPrevView(val);
     242             :         }
     243           0 : }
     244             : 
     245           0 : Rc<ScrollView> MultiViewLayout::makeInitialView() {
     246           0 :         return _generator->makeIndexView(_currentViewIndex);
     247             : }
     248             : 
     249           0 : bool MultiViewLayout::onSwipeProgress() {
     250           0 :         if (!_currentView) {
     251           0 :                 return false;
     252             :         }
     253             : 
     254           0 :         _currentView->setPositionX(_swipeProgress);
     255             : 
     256           0 :         if (_swipeProgress > 0.0f) {
     257           0 :                 if (_nextView) {
     258           0 :                         _nextView->removeFromParent();
     259           0 :                         _nextView = nullptr;
     260             :                 }
     261             : 
     262           0 :                 if (!_prevView) {
     263             :                         //log::format("MultiViewLayout", "prevView %d", _currentViewIndex - 1);
     264           0 :                         if (auto view = _generator->makePrevView(_currentView, _currentViewIndex)) {
     265           0 :                                 onPrevViewCreated(_currentView, view);
     266           0 :                                 _prevView = addChild(view, _currentView->getLocalZOrder());
     267           0 :                         }
     268             :                 }
     269             : 
     270           0 :                 if (!_prevView) {
     271           0 :                         return false;
     272             :                 }
     273             : 
     274           0 :                 if (_prevView) {
     275           0 :                         applyViewProgress(_currentView, _prevView, fabs(_swipeProgress) / _contentSize.width);
     276             :                 }
     277           0 :         } else if (_swipeProgress < 0.0f) {
     278           0 :                 if (_prevView) {
     279           0 :                         _prevView->removeFromParent();
     280           0 :                         _prevView = nullptr;
     281             :                 }
     282             : 
     283           0 :                 if (!_nextView) {
     284           0 :                         if (auto view = _generator->makeNextView(_currentView, _currentViewIndex)) {
     285           0 :                                 onNextViewCreated(_currentView, view);
     286           0 :                                 _nextView = addChild(view, _currentView->getLocalZOrder());
     287           0 :                         }
     288             :                 }
     289             : 
     290           0 :                 if (!_nextView) {
     291           0 :                         return false;
     292             :                 }
     293             : 
     294           0 :                 if (_nextView) {
     295           0 :                         applyViewProgress(_currentView, _nextView, fabs(_swipeProgress) / _contentSize.width);
     296             :                 }
     297             :         } else {
     298           0 :                 if (_nextView) {
     299           0 :                         _nextView->removeFromParent();
     300           0 :                         _nextView = nullptr;
     301             :                 }
     302             : 
     303           0 :                 if (_prevView) {
     304           0 :                         _prevView->removeFromParent();
     305           0 :                         _prevView = nullptr;
     306             :                 }
     307             : 
     308           0 :                 applyView(_currentView);
     309             :         }
     310           0 :         if (_nextView) {
     311           0 :                 _nextView->setPositionX(_swipeProgress + _contentSize.width);
     312             :         }
     313           0 :         if (_prevView) {
     314           0 :                 _prevView->setPositionX(_swipeProgress - _contentSize.width);
     315             :         }
     316           0 :         return true;
     317             : }
     318             : 
     319           0 : bool MultiViewLayout::beginSwipe(const Vec2 &diff) {
     320           0 :         if (_currentView) {
     321           0 :                 if (_generator->isViewLocked(_currentView, _currentViewIndex)) {
     322           0 :                         return false;
     323             :                 }
     324             :         } else {
     325           0 :                 return false;
     326             :         }
     327           0 :         if (_swipeProgress > _contentSize.width * 0.75f && _prevView) {
     328           0 :                 setPrevView(_currentViewIndex - 1, _swipeProgress - _contentSize.width);
     329           0 :         } else if (_swipeProgress < -_contentSize.width * 0.75f && _nextView) {
     330           0 :                 setNextView(_currentViewIndex + 1, _swipeProgress + _contentSize.width);
     331             :         }
     332           0 :         if (fabs(diff.x) < fabs(diff.y)) {
     333           0 :                 return false;
     334             :         } else {
     335           0 :                 setFlexibleLevelAnimated(1.0f, 0.25f);
     336             :         }
     337           0 :         return true;
     338             : }
     339             : 
     340           0 : bool MultiViewLayout::setSwipeProgress(const Vec2 &delta) {
     341           0 :         _currentView->stopActionByTag("ListAction"_tag);
     342           0 :         float diff = delta.x;
     343           0 :         if (!_generator->isInfinite()) {
     344           0 :                 if (_currentViewIndex == 0 && _swipeProgress + diff > 0.0f) {
     345           0 :                         _swipeProgress = 0.0f;
     346           0 :                         onSwipeProgress();
     347           0 :                 } else if (_currentViewIndex == _generator->getViewCount() - 1 && _swipeProgress + diff < 0.0f) {
     348           0 :                         _swipeProgress = 0.0f;
     349           0 :                         onSwipeProgress();
     350             :                 } else {
     351           0 :                         _swipeProgress += diff;
     352           0 :                         onSwipeProgress();
     353             :                 }
     354             :         } else {
     355           0 :                 _swipeProgress += diff;
     356           0 :                 if (!onSwipeProgress()) {
     357           0 :                         _swipeProgress = 0.0f;
     358           0 :                         onSwipeProgress();
     359           0 :                         return false;
     360             :                 }
     361             :         }
     362           0 :         return true;
     363             : }
     364             : 
     365           0 : bool MultiViewLayout::endSwipeProgress(const Vec2 &delta, const Vec2 &velocity) {
     366           0 :         if (!_currentView) {
     367           0 :                 return false;
     368             :         }
     369             :         /*if (fabsf(_swipeProgress) < 20.0f) {
     370             :                 _swipeProgress = 0.0f;
     371             :                 onSwipeProgress();
     372             :                 return false;
     373             :         }*/
     374             : 
     375           0 :         float v = fabsf(velocity.x);
     376           0 :         float a = 5000;
     377           0 :         float t = v / a;
     378           0 :         float dx = v * t - (a * t * t) / 2;
     379             : 
     380           0 :         float pos = _swipeProgress + ((velocity.x > 0) ? (dx) : (-dx));
     381             : 
     382           0 :         float yPos = _currentView->getPosition().y;
     383             : 
     384           0 :         auto from = Vec2(_swipeProgress, yPos);
     385             : 
     386           0 :         Rc<ActionInterval> action;
     387           0 :         if (pos > _contentSize.width / 2 && _prevView) {
     388           0 :                 action = Rc<Sequence>::create(
     389           0 :                                 ActionAcceleratedMove::createBounce(5000, from, Vec2(_contentSize.width, yPos), Vec2(velocity.x, 0),
     390           0 :                                                 200000, std::bind(&MultiViewLayout::onSwipeAction, this, std::placeholders::_1)),
     391           0 :                                 [this] {
     392           0 :                         setPrevView(_currentViewIndex - 1);
     393           0 :                 });
     394           0 :         } else if (pos < -_contentSize.width / 2 && _nextView) {
     395           0 :                 action = Rc<Sequence>::create(
     396           0 :                                 ActionAcceleratedMove::createBounce(5000, from, Vec2(-_contentSize.width, yPos), Vec2(velocity.x, 0),
     397           0 :                                                 200000, std::bind(&MultiViewLayout::onSwipeAction, this, std::placeholders::_1)),
     398           0 :                                 [this] {
     399           0 :                         setNextView(_currentViewIndex + 1);
     400           0 :                 });
     401           0 :         } else {
     402           0 :                 if (from != Vec2(0, yPos)) {
     403           0 :                         action = Rc<Sequence>::create(
     404           0 :                                         ActionAcceleratedMove::createBounce(5000, from, Vec2(0, yPos), Vec2(velocity.x, 0), 50000,
     405           0 :                                                         std::bind(&MultiViewLayout::onSwipeAction, this, std::placeholders::_1)),
     406           0 :                                         [this] {
     407           0 :                                 _swipeProgress = 0;
     408           0 :                                 onSwipeProgress();
     409           0 :                         });
     410             :                 } else {
     411           0 :                         _swipeProgress = 0;
     412           0 :                         onSwipeProgress();
     413           0 :                         onViewSelected(_currentView, _currentViewIndex);
     414             :                 }
     415             :         }
     416           0 :         if (action) {
     417           0 :                 _currentView->runAction(action, "ListAction"_tag);
     418             :         }
     419           0 :         return true;
     420           0 : }
     421             : 
     422           0 : void MultiViewLayout::onSwipeAction(Node *node) {
     423           0 :         if (node == _currentView) {
     424           0 :                 _swipeProgress = _currentView->getPosition().x;
     425           0 :                 onSwipeProgress();
     426             :         }
     427           0 : }
     428             : 
     429           0 : void MultiViewLayout::setNextView(int64_t id, float newProgress) {
     430           0 :         _currentViewIndex = id;
     431           0 :         if (_nextView) {
     432           0 :                 _currentView = _nextView;
     433           0 :                 _nextView = nullptr;
     434             : 
     435           0 :                 onViewSelected(_currentView, id);
     436           0 :                 setBaseNode(_currentView, ZOrder(1));
     437             :         }
     438           0 :         _swipeProgress = newProgress;
     439           0 :         onSwipeProgress();
     440           0 : }
     441             : 
     442           0 : void MultiViewLayout::setPrevView(int64_t id, float newProgress) {
     443           0 :         _currentViewIndex = id;
     444           0 :         if (_prevView) {
     445           0 :                 _currentView = _prevView;
     446           0 :                 _prevView = nullptr;
     447             : 
     448           0 :                 onViewSelected(_currentView, id);
     449           0 :                 setBaseNode(_currentView, ZOrder(1));
     450             :         }
     451           0 :         _swipeProgress = newProgress;
     452           0 :         onSwipeProgress();
     453           0 : }
     454             : 
     455           0 : void MultiViewLayout::onViewSelected(ScrollView *current, int64_t id) {
     456           0 :         _generator->onViewSelected(current, id);
     457           0 : }
     458             : 
     459           0 : void MultiViewLayout::onPrevViewCreated(ScrollView *current, ScrollView *prev) {
     460           0 :         prev->setContentSize(current->getContentSize());
     461           0 :         prev->setPosition(current->getPosition());
     462           0 :         prev->setPadding(current->getPadding());
     463           0 :         _generator->onViewCreated(prev, _currentViewIndex - 1);
     464           0 : }
     465             : 
     466           0 : void MultiViewLayout::onNextViewCreated(ScrollView *current, ScrollView *next) {
     467           0 :         next->setContentSize(current->getContentSize());
     468           0 :         next->setPosition(current->getPosition());
     469           0 :         next->setPadding(current->getPadding());
     470           0 :         _generator->onViewCreated(next, _currentViewIndex + 1);
     471           0 : }
     472             : 
     473           0 : void MultiViewLayout::applyView(ScrollView *current) {
     474           0 :         _generator->onApplyView(current, _currentViewIndex);
     475           0 : }
     476             : 
     477           0 : void MultiViewLayout::applyViewProgress(ScrollView *current, ScrollView *n, float p) {
     478           0 :         _generator->onApplyProgress(current, n, p);
     479           0 : }
     480             : 
     481           0 : void MultiViewLayout::onBaseNode(const NodeParams &params, const Padding &padding, float offset) {
     482           0 :         FlexibleLayout::onBaseNode(params, padding, offset);
     483             : 
     484           0 :         if (_swipeProgress != 0.0f)  {
     485           0 :                 _currentView->setPositionX(_swipeProgress);
     486             :         }
     487           0 : }
     488             : 
     489             : }

Generated by: LCOV version 1.14