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

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 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 "XLInputListener.h"
      24             : #include "XL2dActionAcceleratedMove.h"
      25             : #include "XL2dImageLayer.h"
      26             : #include "XLTexture.h"
      27             : 
      28             : namespace STAPPLER_VERSIONIZED stappler::xenolith::basic2d {
      29             : 
      30           0 : Rect ImageLayer::getCorrectRect(Size2 containerSize) {
      31           0 :         Size2 parentSize = getContentSize();
      32           0 :         Rect ret = Rect(parentSize.width - containerSize.width,
      33           0 :                         parentSize.height - containerSize.height,
      34           0 :                         containerSize.width - parentSize.width,
      35           0 :                         containerSize.height - parentSize.height);
      36             : 
      37           0 :         if (containerSize.width <= parentSize.width) {
      38           0 :                 ret.origin.x = (parentSize.width - containerSize.width) / 2;
      39           0 :                 ret.size.width = 0;
      40             :         }
      41             : 
      42           0 :         if (containerSize.height <= parentSize.height) {
      43           0 :                 ret.origin.y = (parentSize.height - containerSize.height) / 2;
      44           0 :                 ret.size.height = 0;
      45             :         }
      46             : 
      47           0 :         if (isnan(containerSize.width) || isnan(containerSize.height)) {
      48           0 :                 log::format(log::LogType::Error, "ImageLayer", "rect %f %f %f %f : %f %f %f %f",
      49           0 :                                 parentSize.width, parentSize.height, containerSize.width, containerSize.height,
      50           0 :                                 ret.origin.x, ret.origin.y, ret.size.width, ret.size.height);
      51             :         }
      52             : 
      53           0 :         return ret;
      54             : }
      55             : 
      56           0 : Vec2 ImageLayer::getCorrectPosition(Size2 containerSize, Vec2 point) {
      57           0 :         Vec2 ret = point;
      58           0 :         Rect bounds = getCorrectRect(containerSize);
      59             : 
      60           0 :         if (ret.x < bounds.origin.x) {
      61           0 :                 ret.x = bounds.origin.x;
      62           0 :         } else if (ret.x > bounds.getMaxX()) {
      63           0 :                 ret.x = bounds.getMaxX();
      64             :         }
      65             : 
      66           0 :         if (ret.y < bounds.origin.y) {
      67           0 :                 ret.y = bounds.origin.y;
      68           0 :         } else if (ret.y > bounds.getMaxY()) {
      69           0 :                 ret.y = bounds.getMaxY();
      70             :         }
      71             : 
      72           0 :         if (isnan(ret.x) || isnan(ret.y)) {
      73           0 :                 log::format(log::LogType::Error, "ImageLayer", "pos %f %f %f %f : %f %f : %f %f",
      74           0 :                                 bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height,
      75           0 :                                 point.x, point.y, ret.x, ret.y);
      76             :         }
      77           0 :         return ret;
      78             : }
      79             : 
      80           0 : Size2 ImageLayer::getContainerSize() const {
      81           0 :         return Size2(
      82           0 :                         _root->getContentSize().width * _root->getScale().x,
      83           0 :                         _root->getContentSize().height * _root->getScale().y);
      84             : }
      85             : 
      86           0 : Size2 ImageLayer::getContainerSizeForScale(float value) const {
      87           0 :         return Size2(
      88           0 :                         _root->getContentSize().width * value,
      89           0 :                         _root->getContentSize().height * value);
      90             : }
      91             : 
      92           0 : ImageLayer::~ImageLayer() { }
      93             : 
      94           0 : bool ImageLayer::init() {
      95           0 :         if (!Node::init()) {
      96           0 :                 return false;
      97             :         }
      98             : 
      99           0 :         setOpacity(1.0f);
     100           0 :         _gestureListener = addInputListener(Rc<InputListener>::create());
     101           0 :         _gestureListener->setTouchFilter([] (const InputEvent &ev, const InputListener::DefaultEventFilter &f) {
     102           0 :                 return f(ev);
     103             :         });
     104           0 :         _gestureListener->addTapRecognizer([this] (const GestureTap &tap) {
     105           0 :                 if (_actionCallback) {
     106           0 :                         _actionCallback();
     107             :                 }
     108           0 :                 return handleTap(tap.input->currentLocation, tap.count);
     109             :         });
     110           0 :         _gestureListener->addSwipeRecognizer([this] (const GestureSwipe &s) {
     111           0 :                 if (s.event == GestureEvent::Began) {
     112           0 :                         if (_actionCallback) {
     113           0 :                                 _actionCallback();
     114             :                         }
     115           0 :                         return handleSwipeBegin(s.input->currentLocation);
     116           0 :                 } else if (s.event == GestureEvent::Activated) {
     117           0 :                         return handleSwipe(Vec2(s.delta.x / _globalScale.x, s.delta.y / _globalScale.y));
     118           0 :                 } else if (s.event == GestureEvent::Ended) {
     119           0 :                         return handleSwipeEnd(Vec2(s.velocity.x / _globalScale.x, s.velocity.y / _globalScale.y));
     120             : 
     121             :                 }
     122           0 :                 return true;
     123             :         });
     124           0 :         _gestureListener->addPinchRecognizer([this] (const GesturePinch &p) {
     125           0 :                 if (p.event == GestureEvent::Began) {
     126           0 :                         if (_actionCallback) {
     127           0 :                                 _actionCallback();
     128             :                         }
     129           0 :                         _hasPinch = true;
     130           0 :                 } else if (p.event == GestureEvent::Activated) {
     131           0 :                         return handlePinch(p.center, p.scale, p.velocity, false);
     132           0 :                 } else if (p.event == GestureEvent::Ended || p.event == GestureEvent::Cancelled) {
     133           0 :                         _hasPinch = false;
     134           0 :                         return handlePinch(p.center, p.scale, p.velocity, true);
     135             :                 }
     136           0 :                 return true;
     137             :         });
     138             : 
     139           0 :         _root = addChild(Rc<Node>::create());
     140           0 :         _root->setCascadeOpacityEnabled(true);
     141           0 :         _root->setScale(1.0f);
     142             : 
     143           0 :         _image = _root->addChild(Rc<Sprite>::create(core::EmptyTextureName));
     144             : 
     145           0 :         _scaleSource = 0;
     146             : 
     147           0 :         return true;
     148             : }
     149             : 
     150           0 : void ImageLayer::onContentSizeDirty() {
     151           0 :         Node::onContentSizeDirty();
     152             : 
     153           0 :         auto imageSize = _image->getTexture()->getExtent();
     154           0 :         if (_imageSizePredefined) {
     155           0 :                 imageSize = Extent3(_imageSize.width, _imageSize.height, 1);
     156             :         }
     157           0 :         _root->setContentSize(Size2(imageSize.width, imageSize.height));
     158             : 
     159           0 :         if (!_scaleDisabled) {
     160           0 :                 _minScale = std::min(
     161           0 :                                 _contentSize.width / _image->getContentSize().width,
     162           0 :                                 _contentSize.height / _image->getContentSize().height);
     163             : 
     164           0 :                 _maxScale = std::max(
     165           0 :                                 _image->getContentSize().width * GetMaxScaleFactor() / _contentSize.width,
     166           0 :                                 _image->getContentSize().height * GetMaxScaleFactor() / _contentSize.height);
     167             :         } else {
     168           0 :                 _minScale = _maxScale = 1.0f;
     169             :         }
     170             : 
     171           0 :         if (_textureDirty) {
     172           0 :                 _textureDirty = false;
     173           0 :                 _root->setScale(_minScale);
     174             :         }
     175             : 
     176           0 :         Vec2 prevCenter = Vec2(_prevContentSize.width / 2.0f, _prevContentSize.height / 2.0f);
     177           0 :         Vec2 center = Vec2(_contentSize.width / 2.0f, _contentSize.height / 2.0f);
     178           0 :         Vec2 offset = center - prevCenter;
     179             : 
     180           0 :         _root->setPosition(getCorrectPosition(getContainerSize(), _root->getPosition().xy() + offset));
     181             : 
     182           0 :         auto currentScale = _root->getScale().x;
     183           0 :         if (_maxScale != 0 && _minScale != 0 && (currentScale > _maxScale || currentScale < _minScale)) {
     184           0 :                 float newScale = currentScale;
     185           0 :                 if (_minScale > _maxScale) {
     186           0 :                         newScale = _minScale;
     187           0 :                 } else if (currentScale < _minScale) {
     188           0 :                         newScale = _minScale;
     189           0 :                 } else if (currentScale > _maxScale) {
     190           0 :                         newScale = _maxScale;
     191             :                 }
     192           0 :                 Vec2 pos = _root->getPosition().xy();
     193           0 :                 Vec2 locInParent = Vec2(_contentSize.width / 2.0f, _contentSize.height / 2.0f);
     194             : 
     195           0 :                 Vec2 normal = (pos - locInParent) / currentScale * newScale;
     196             : 
     197           0 :                 _root->setScale(newScale);
     198           0 :                 _root->setPosition(getCorrectPosition(getContainerSize(), locInParent + normal));
     199             :         }
     200             : 
     201           0 :         _prevContentSize = _contentSize;
     202           0 :         _root->setPosition(getCorrectPosition(getContainerSize(), _root->getPosition().xy()));
     203           0 : }
     204             : 
     205           0 : void ImageLayer::onTransformDirty(const Mat4 &parentTransform) {
     206           0 :         Node::onTransformDirty(parentTransform);
     207           0 :         Vec3 scale;
     208           0 :         getNodeToWorldTransform().getScale(&scale);
     209           0 :         _globalScale = Vec2(scale.x, scale.y);
     210           0 : }
     211             : 
     212           0 : void ImageLayer::setTexture(Rc<Texture> &&tex) {
     213           0 :         _imageSizePredefined = false;
     214             : 
     215           0 :         auto extent = tex->getExtent();
     216           0 :         _image->setTexture(move(tex));
     217           0 :         _image->setContentSize(Size2(extent.width, extent.height));
     218             : 
     219           0 :         if (_contentSize.width == 0.0f || _contentSize.height == 0.0f) {
     220           0 :                 _minScale = 1.0f;
     221           0 :                 _maxScale = 1.0f;
     222           0 :                 _root->setScale(1.0f);
     223           0 :                 _contentSizeDirty = true;
     224           0 :                 _textureDirty = true;
     225           0 :                 return;
     226             :         }
     227             : 
     228           0 :         if (_running) {
     229           0 :                 if (!_scaleDisabled) {
     230           0 :                         _minScale = std::min(
     231           0 :                                         _contentSize.width / _image->getContentSize().width,
     232           0 :                                         _contentSize.height / _image->getContentSize().height);
     233             : 
     234           0 :                         _maxScale = std::max(
     235           0 :                                         _image->getContentSize().width * GetMaxScaleFactor() / _contentSize.width,
     236           0 :                                         _image->getContentSize().height * GetMaxScaleFactor() / _contentSize.height);
     237             : 
     238           0 :                         _root->setScale(_minScale);
     239             :                 } else {
     240           0 :                         _minScale = _maxScale = 1.0f;
     241           0 :                         Size2 imageSize = _image->getBoundingBox().size;
     242           0 :                         _root->setContentSize(imageSize);
     243           0 :                         _root->setScale(1.0f);
     244           0 :                         _root->setPosition(getCorrectPosition(getContainerSize(),
     245           0 :                                         Vec2((_contentSize.width - imageSize.width) / 2.0f, _contentSize.height - imageSize.height)));
     246             :                 }
     247             : 
     248           0 :                 _contentSizeDirty = true;
     249             :         } else {
     250           0 :                 _textureDirty = true;
     251             :         }
     252             : }
     253             : 
     254           0 : const Rc<Texture> &ImageLayer::getTexture() const {
     255           0 :         return _image->getTexture();
     256             : }
     257             : 
     258           0 : void ImageLayer::setActionCallback(Function<void()> &&cb) {
     259           0 :         _actionCallback = move(cb);
     260           0 : }
     261             : 
     262           0 : Vec2 ImageLayer::getTexturePosition() const {
     263           0 :         auto csize = getContainerSize();
     264           0 :         auto bsize = getContentSize();
     265           0 :         auto vec = _root->getPosition();
     266           0 :         bsize = Size2(csize.width - bsize.width, csize.height - bsize.height);
     267           0 :         Vec2 result;
     268           0 :         if (bsize.width <= 0) {
     269           0 :                 bsize.width = 0;
     270           0 :                 result.x = nan();
     271             :         } else {
     272           0 :                 result.x = fabs(-vec.x / bsize.width);
     273             :         }
     274           0 :         if (bsize.height <= 0) {
     275           0 :                 bsize.height = 0;
     276           0 :                 result.y = nan();
     277             :         } else {
     278           0 :                 result.y = fabs(-vec.y / bsize.height);
     279             :         }
     280             : 
     281           0 :         return result;
     282             : }
     283             : 
     284           0 : void ImageLayer::setScaleDisabled(bool value) {
     285           0 :         if (_scaleDisabled != value) {
     286           0 :                 _scaleDisabled = value;
     287           0 :                 _contentSizeDirty = true;
     288             :         }
     289           0 : }
     290             : 
     291           0 : void ImageLayer::setImageSize(Size2 size) {
     292           0 :         _imageSize = size;
     293           0 :         _imageSizePredefined = true;
     294           0 :         _contentSizeDirty = true;
     295           0 :         _textureDirty = true;
     296           0 : }
     297             : 
     298           0 : bool ImageLayer::handleTap(Vec2 point, int count) {
     299           0 :         if (count == 2 && !_scaleDisabled) {
     300           0 :                 if (_root->getScale().x > _minScale) {
     301           0 :                         Vec2 location = convertToNodeSpace(point);
     302             : 
     303           0 :                         float newScale = _minScale;
     304           0 :                         float origScale = _root->getScale().x;
     305           0 :                         Vec2 pos = _root->getPosition().xy();
     306           0 :                         Vec2 locInParent = convertToNodeSpace(location);
     307             : 
     308           0 :                         Vec2 normal = (pos - locInParent) / origScale * newScale;
     309           0 :                         Vec2 newPos = getCorrectPosition(getContainerSizeForScale(newScale), locInParent + normal);
     310             : 
     311           0 :                         _root->runAction(Rc<Spawn>::create(
     312           0 :                                 Rc<ScaleTo>::create(0.35, newScale),
     313           0 :                                 Rc<MoveTo>::create(0.35, newPos)));
     314             :                 } else {
     315           0 :                         Vec2 location = convertToNodeSpace(point);
     316             : 
     317           0 :                         float newScale = _minScale * 2.0f * _inputDensity;
     318           0 :                         float origScale = _root->getScale().x;
     319             : 
     320           0 :                         if (_minScale > _maxScale) {
     321           0 :                                 newScale = _minScale;
     322           0 :                         } else if (newScale < _minScale) {
     323           0 :                                 newScale = _minScale;
     324           0 :                         } else if (newScale > _maxScale) {
     325           0 :                                 newScale = _maxScale;
     326             :                         }
     327             : 
     328           0 :                         Vec2 pos = _root->getPosition().xy();
     329           0 :                         Vec2 locInParent = convertToNodeSpace(location);
     330             : 
     331           0 :                         Vec2 normal = (pos - locInParent) * (newScale / origScale) * _inputDensity;
     332           0 :                         Vec2 newPos = getCorrectPosition(getContainerSizeForScale(newScale), locInParent + normal);
     333             : 
     334           0 :                         _root->runAction(Rc<Spawn>::create(
     335           0 :                                 Rc<ScaleTo>::create(0.35, newScale),
     336           0 :                                 Rc<MoveTo>::create(0.35, newPos)));
     337             :                 }
     338             :         }
     339           0 :         return true;
     340             : }
     341             : 
     342           0 : bool ImageLayer::handleSwipeBegin(Vec2 point) {
     343           0 :         return true;
     344             : }
     345             : 
     346           0 : bool ImageLayer::handleSwipe(Vec2 delta) {
     347           0 :         Vec2 containerPosition = _root->getPosition().xy();
     348           0 :         _root->stopAllActions();
     349           0 :         _root->setPosition(getCorrectPosition(getContainerSize(), containerPosition + delta));
     350           0 :         return true;
     351             : }
     352             : 
     353           0 : bool ImageLayer::handleSwipeEnd(Vec2 velocity) {
     354           0 :         _root->stopAllActions();
     355           0 :         auto a = ActionAcceleratedMove::createWithBounds(5000, _root->getPosition().xy(), velocity, getCorrectRect(_root->getBoundingBox().size));
     356           0 :         if (a) {
     357           0 :                 _root->runAction(Rc<Sequence>::create(move(a), [this] {
     358           0 :                         _contentSizeDirty = true;
     359           0 :                 }));
     360             :         }
     361           0 :         return true;
     362           0 : }
     363             : 
     364           0 : bool ImageLayer::handlePinch(Vec2 location, float scale, float velocity, bool isEnded) {
     365           0 :         if (isEnded) {
     366           0 :                 _contentSizeDirty = true;
     367           0 :                 _scaleSource = 0;
     368           0 :                 return true;
     369           0 :         } else if (_scaleSource == 0) {
     370           0 :                 _scaleSource = _root->getScale().x;
     371             :         }
     372             : 
     373           0 :         if (_maxScale < _minScale) {
     374           0 :                 return true;
     375             :         }
     376             : 
     377           0 :         float newScale = _scaleSource * scale;
     378           0 :         if (newScale < _minScale) {
     379           0 :                 newScale = _minScale;
     380             :         }
     381           0 :         if (newScale > _maxScale && _maxScale > _minScale) {
     382           0 :                 newScale = _maxScale;
     383             :         }
     384             : 
     385           0 :         float origScale = _root->getScale().x;
     386           0 :         Vec2 pos = _root->getPosition().xy();
     387           0 :         Vec2 locInParent = convertToNodeSpace(location);
     388             : 
     389           0 :         Vec2 normal = (pos - locInParent) / origScale * newScale;
     390             : 
     391           0 :         _root->setScale(newScale);
     392           0 :         _root->setPosition(getCorrectPosition(getContainerSize(), locInParent + normal));
     393             : 
     394           0 :         return true;
     395             : }
     396             : 
     397             : }

Generated by: LCOV version 1.14