LCOV - code coverage report
Current view: top level - xenolith/renderer/material2d/layout - MaterialFlexibleLayout.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 173 339 51.0 %
Date: 2024-05-12 00:16:13 Functions: 24 47 51.1 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023-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 "MaterialFlexibleLayout.h"
      24             : #include "MaterialEasing.h"
      25             : #include "MaterialAppBar.h"
      26             : #include "MaterialButton.h"
      27             : #include "XL2dSceneContent.h"
      28             : #include "XLDirector.h"
      29             : #include "XLView.h"
      30             : #include "XLAction.h"
      31             : 
      32             : namespace STAPPLER_VERSIONIZED stappler::xenolith::material2d {
      33             : 
      34         144 : void FlexibleLayout::NodeParams::setPosition(float x, float y) {
      35         144 :         setPosition(Vec2(x, y));
      36         144 : }
      37             : 
      38         144 : void FlexibleLayout::NodeParams::setPosition(const Vec2 &pos) {
      39         144 :         position = pos;
      40         144 :         mask = Mask(mask | Mask::Position);
      41         144 : }
      42             : 
      43         144 : void FlexibleLayout::NodeParams::setAnchorPoint(const Vec2 &pt) {
      44         144 :         anchorPoint = pt;
      45         144 :         mask = Mask(mask | Mask::AnchorPoint);
      46         144 : }
      47             : 
      48         144 : void FlexibleLayout::NodeParams::setContentSize(const Size2 &size) {
      49         144 :         contentSize = size;
      50         144 :         mask = Mask(mask | Mask::ContentSize);
      51         144 : }
      52             : 
      53         144 : void FlexibleLayout::NodeParams::setVisible(bool value) {
      54         144 :         visible = value;
      55         144 :         mask = Mask(mask | Mask::Visibility);
      56         144 : }
      57             : 
      58         132 : void FlexibleLayout::NodeParams::apply(Node *node) const {
      59         132 :         if (mask & Mask::AnchorPoint) {
      60          60 :                 node->setAnchorPoint(anchorPoint);
      61             :         }
      62         132 :         if (mask & Mask::Position) {
      63          60 :                 node->setPosition(position);
      64             :         }
      65         132 :         if (mask & Mask::ContentSize) {
      66          60 :                 node->setContentSize(contentSize);
      67             :         }
      68         132 :         if (mask & Mask::Visibility) {
      69         102 :                 node->setVisible(visible);
      70             :         }
      71         132 : }
      72             : 
      73          52 : bool FlexibleLayout::init() {
      74          52 :         if (!DecoratedLayout::init()) {
      75           0 :                 return false;
      76             :         }
      77             : 
      78          52 :         setCascadeOpacityEnabled(true);
      79             : 
      80          52 :         return true;
      81             : }
      82             : 
      83          52 : void FlexibleLayout::onContentSizeDirty() {
      84          52 :         DecoratedLayout::onContentSizeDirty();
      85             : 
      86          52 :         float realFlexMin = _targetFlexibleMinHeight;
      87          52 :         float realFlexMax = _targetFlexibleMaxHeight;
      88             : 
      89          52 :         if (_flexibleNode) {
      90          10 :                 auto heightLimit = _flexibleNode->getHeightLimits(true);
      91          10 :                 if (!isnan(heightLimit.first)) {
      92          10 :                         realFlexMin = std::max(heightLimit.first, realFlexMin);
      93             :                 }
      94             : 
      95          10 :                 if (!isnan(heightLimit.second)) {
      96          10 :                         realFlexMax = std::max(heightLimit.second, realFlexMax);
      97             :                 }
      98             :         }
      99             : 
     100          52 :         if (_flexibleHeightFunction) {
     101           0 :                 auto ret = _flexibleHeightFunction();
     102           0 :                 realFlexMin = std::max(ret.first, realFlexMin);
     103           0 :                 realFlexMax = std::min(ret.second, realFlexMax);
     104             :         }
     105             : 
     106          52 :         _realFlexibleMinHeight = realFlexMin;
     107          52 :         _realFlexibleMaxHeight = realFlexMax;
     108             : 
     109          52 :         _flexibleExtraSpace = 0.0f;
     110          52 :         updateFlexParams();
     111          52 : }
     112             : 
     113          10 : void FlexibleLayout::setBaseNode(ScrollView *node, ZOrder zOrder) {
     114          10 :         if (node != _baseNode) {
     115          10 :                 if (_baseNode) {
     116           0 :                         _baseNode->removeFromParent();
     117           0 :                         _baseNode = nullptr;
     118             :                 }
     119          10 :                 _baseNode = node;
     120          10 :                 if (_baseNode) {
     121          10 :                         _baseNode->setScrollCallback(std::bind(&FlexibleLayout::onScroll, this,
     122             :                                         std::placeholders::_1, std::placeholders::_2));
     123          10 :                         if (_baseNode->isVertical()) {
     124          10 :                                 _baseNode->setOverscrollFrontOffset(getCurrentFlexibleHeight());
     125             :                         }
     126          10 :                         if (!_baseNode->getParent()) {
     127          10 :                                 addChild(_baseNode, zOrder);
     128             :                         }
     129             :                 }
     130          10 :                 _contentSizeDirty = true;
     131             :         }
     132          10 : }
     133             : 
     134          10 : void FlexibleLayout::setFlexibleNode(Surface *node, ZOrder zOrder) {
     135          10 :         if (node != _flexibleNode) {
     136          10 :                 if (_flexibleNode) {
     137           0 :                         _flexibleNode->removeFromParent();
     138           0 :                         _flexibleNode = nullptr;
     139             :                 }
     140          10 :                 _flexibleNode = node;
     141          10 :                 _appBar = nullptr;
     142          10 :                 if (_flexibleNode) {
     143          10 :                         if (auto bar = dynamic_cast<AppBar *>(_flexibleNode)) {
     144          10 :                                 _appBar = bar;
     145             :                         }
     146          10 :                         addChild(_flexibleNode, zOrder);
     147             :                 }
     148          10 :                 _contentSizeDirty = true;
     149             :         }
     150          10 : }
     151             : 
     152           0 : void FlexibleLayout::setFlexibleAutoComplete(bool value) {
     153           0 :         if (_flexibleAutoComplete != value) {
     154           0 :                 _flexibleAutoComplete = value;
     155             :         }
     156           0 : }
     157             : 
     158          10 : void FlexibleLayout::setFlexibleMinHeight(float height) {
     159          10 :         if (_targetFlexibleMinHeight != height) {
     160           0 :                 _targetFlexibleMinHeight = height;
     161           0 :                 _contentSizeDirty = true;
     162             :         }
     163          10 : }
     164             : 
     165          10 : void FlexibleLayout::setFlexibleMaxHeight(float height) {
     166          10 :         if (_targetFlexibleMaxHeight != height) {
     167          10 :                 _targetFlexibleMaxHeight = height;
     168          10 :                 _contentSizeDirty = true;
     169             :         }
     170          10 : }
     171             : 
     172           0 : float FlexibleLayout::getFlexibleMinHeight() const {
     173           0 :         return _targetFlexibleMinHeight;
     174             : }
     175             : 
     176           0 : float FlexibleLayout::getFlexibleMaxHeight() const {
     177           0 :         return _targetFlexibleMaxHeight;
     178             : }
     179             : 
     180           0 : void FlexibleLayout::setFlexibleBaseNode(bool val) {
     181           0 :         if (_flexibleBaseNode != val) {
     182           0 :                 _flexibleBaseNode = val;
     183           0 :                 _contentSizeDirty = true;
     184             :         }
     185           0 : }
     186             : 
     187           0 : bool FlexibleLayout::isFlexibleBaseNode() const {
     188           0 :         return _flexibleBaseNode;
     189             : }
     190             : 
     191           0 : void FlexibleLayout::setFlexibleHeightFunction(const HeightFunction &cb) {
     192           0 :         _flexibleHeightFunction = cb;
     193           0 :         if (cb) {
     194           0 :                 _contentSizeDirty = true;
     195           0 :                 _flexibleLevel = 1.0f;
     196             :         }
     197           0 : }
     198             : 
     199           0 : const FlexibleLayout::HeightFunction &FlexibleLayout::getFlexibleHeightFunction() const {
     200           0 :         return _flexibleHeightFunction;
     201             : }
     202             : 
     203          72 : void FlexibleLayout::updateFlexParams() {
     204          72 :         NodeParams decorParams, flexibleNodeParams, baseNodeParams;
     205             : 
     206          72 :         bool tracked = (_viewDecoration & ViewDecorationFlags::Tracked) != ViewDecorationFlags::None;
     207          72 :         bool hasTopDecor = (_decorationMask & DecorationMask::Top) != DecorationMask::None;
     208          72 :         auto size = _contentSize;
     209          72 :         size.height -= _decorationPadding.bottom;
     210          72 :         float decor = tracked ? _decorationPadding.top : 0.0f;
     211          72 :         float flexSize = _realFlexibleMinHeight + (_realFlexibleMaxHeight + decor - _realFlexibleMinHeight) * _flexibleLevel;
     212             : 
     213          72 :         if (flexSize >= _realFlexibleMaxHeight && tracked) {
     214           0 :                 float tmpDecor = (flexSize - _realFlexibleMaxHeight);
     215           0 :                 decorParams.setContentSize(Size2(_contentSize.width - _decorationPadding.horizontal(), tmpDecor));
     216           0 :                 size.height -= tmpDecor;
     217           0 :                 flexSize = _realFlexibleMaxHeight;
     218           0 :                 decorParams.setPosition(Vec2(_decorationPadding.left, _contentSize.height));
     219           0 :                 decorParams.setVisible(true);
     220          72 :         } else if (tracked) {
     221           0 :                 decorParams.setVisible(false);
     222             :         } else {
     223          72 :                 decorParams.setVisible(hasTopDecor);
     224          72 :                 if (hasTopDecor) {
     225          72 :                         size.height -= _decorationPadding.top;
     226             :                 }
     227             :         }
     228             : 
     229          72 :         flexibleNodeParams.setPosition(_decorationPadding.left, size.height + _decorationPadding.bottom);
     230          72 :         flexibleNodeParams.setAnchorPoint(Vec2(0, 1));
     231          72 :         flexibleNodeParams.setContentSize(Size2(size.width - _decorationPadding.horizontal(), flexSize + _flexibleExtraSpace));
     232          72 :         flexibleNodeParams.setVisible(flexSize > 0.0f);
     233             : 
     234          72 :         if (tracked && _sceneContent) {
     235           0 :                 if (_flexibleLevel == 1.0f) {
     236           0 :                         _sceneContent->showViewDecoration();
     237             :                 } else {
     238           0 :                         _sceneContent->hideViewDecoration();
     239             :                 }
     240             :         }
     241             : 
     242          72 :         Padding padding;
     243          72 :         if (_baseNode) {
     244          30 :                 padding = _baseNode->getPadding();
     245             :         }
     246             : 
     247          72 :         float baseNodeOffset = getCurrentFlexibleHeight();
     248          72 :         Padding baseNodePadding(padding.setTop(getCurrentFlexibleMax() + _baseNodePadding));
     249             : 
     250          72 :         baseNodeParams.setAnchorPoint(Vec2(0, 0));
     251          72 :         baseNodeParams.setPosition(_decorationPadding.left, _decorationPadding.bottom);
     252             : 
     253          72 :         if (_flexibleBaseNode) {
     254          72 :                 baseNodeParams.setContentSize(Size2(size.width - _decorationPadding.horizontal(), size.height + decor));
     255             :         } else {
     256           0 :                 baseNodeParams.setContentSize(Size2(size.width - _decorationPadding.horizontal(), size.height + decor - getCurrentFlexibleMax() - 0.0f));
     257           0 :                 baseNodePadding = padding.setTop(4.0f);
     258           0 :                 baseNodeOffset = 0.0f;
     259             :         }
     260             : 
     261          72 :         onDecorNode(decorParams);
     262          72 :         onFlexibleNode(flexibleNodeParams);
     263          72 :         onBaseNode(baseNodeParams, baseNodePadding, baseNodeOffset);
     264          72 : }
     265             : 
     266         220 : void FlexibleLayout::onScroll(float delta, bool finished) {
     267         220 :         auto size = _baseNode->getScrollableAreaSize();
     268         220 :         if (!isnan(size) && size < _contentSize.height) {
     269           0 :                 clearFlexibleExpand(0.25f);
     270           0 :                 setFlexibleLevel(1.0f);
     271           0 :                 return;
     272             :         }
     273             : 
     274         220 :         clearFlexibleExpand(0.25f);
     275         220 :         if (!finished && delta != 0.0f) {
     276         220 :                 const auto distanceFromStart = _baseNode->getDistanceFromStart();
     277         220 :                 const auto trigger = _safeTrigger ? ( _realFlexibleMaxHeight - _realFlexibleMinHeight) : 8.0f;
     278         220 :                 if (isnan(distanceFromStart) || distanceFromStart > trigger || delta < 0) {
     279         210 :                         stopActionByTag(FlexibleLayout::AutoCompleteTag());
     280         210 :                         float height = getCurrentFlexibleHeight();
     281             :                         //float diff = delta.y / _baseNode->getGlobalScale().y;
     282         210 :                         float newHeight = height - delta;
     283         210 :                         if (delta < 0) {
     284           0 :                                 float max = getCurrentFlexibleMax();
     285           0 :                                 if (newHeight > max) {
     286           0 :                                         newHeight = max;
     287             :                                 }
     288             :                         } else {
     289         210 :                                 if (newHeight < _realFlexibleMinHeight) {
     290         200 :                                         newHeight = _realFlexibleMinHeight;
     291             :                                 }
     292             :                         }
     293         210 :                         setFlexibleHeight(newHeight);
     294             :                 }
     295         220 :         } else if (finished) {
     296           0 :                 if (_flexibleAutoComplete) {
     297           0 :                         if (_flexibleLevel < 1.0f && _flexibleLevel > 0.0f) {
     298           0 :                                 auto distanceFromStart = _baseNode->getDistanceFromStart();
     299           0 :                                 bool open =  (_flexibleLevel > 0.5) || (!isnan(distanceFromStart) && distanceFromStart < (_realFlexibleMaxHeight - _realFlexibleMinHeight));
     300           0 :                                 auto a = Rc<ActionProgress>::create(progress(0.0f, 0.3f, open?_flexibleLevel:(1.0f - _flexibleLevel)), open?1.0f:0.0f,
     301           0 :                                                 [this] (float p) {
     302           0 :                                         setFlexibleLevel(p);
     303           0 :                                 });
     304           0 :                                 a->setSourceProgress(_flexibleLevel);
     305           0 :                                 a->setTag(FlexibleLayout::AutoCompleteTag());
     306           0 :                                 if (open) {
     307           0 :                                         runAction(makeEasing(move(a), EasingType::StandardAccelerate));
     308             :                                 } else {
     309           0 :                                         runAction(makeEasing(move(a), EasingType::StandardDecelerate));
     310             :                                 }
     311           0 :                         }
     312             :                 }
     313             :         }
     314             : }
     315             : 
     316           0 : float FlexibleLayout::getFlexibleLevel() const {
     317           0 :         return _flexibleLevel;
     318             : }
     319             : 
     320         210 : void FlexibleLayout::setFlexibleLevel(float value) {
     321         210 :         if (value > 1.0f) {
     322           0 :                 value = 1.0f;
     323         210 :         } else if (value < 0.0f) {
     324           0 :                 value = 0.0f;
     325             :         }
     326             : 
     327         210 :         if (value == _flexibleLevel) {
     328         190 :                 return;
     329             :         }
     330             : 
     331          20 :         _flexibleLevel = value;
     332          20 :         updateFlexParams();
     333             : }
     334             : 
     335           0 : void FlexibleLayout::setFlexibleLevelAnimated(float value, float duration) {
     336           0 :         stopActionByTag("FlexibleLevel"_tag);
     337           0 :         if (duration <= 0.0f) {
     338           0 :                 setFlexibleLevel(value);
     339             :         } else {
     340           0 :                 if (_flexibleLevel != value) {
     341           0 :                         auto a = Rc<Sequence>::create(makeEasing(Rc<ActionProgress>::create(
     342           0 :                                         duration, _flexibleLevel, value,
     343           0 :                                         [this] (float progress) {
     344           0 :                                 setFlexibleLevel(progress);
     345           0 :                         }), EasingType::Emphasized), [this, value] {
     346           0 :                                 setFlexibleLevel(value);
     347           0 :                         });
     348           0 :                         a->setTag("FlexibleLevel"_tag);
     349           0 :                         runAction(a);
     350           0 :                 }
     351             :         }
     352           0 : }
     353             : 
     354         210 : void FlexibleLayout::setFlexibleHeight(float height) {
     355         210 :         float size = getCurrentFlexibleMax() - _realFlexibleMinHeight;
     356         210 :         if (size > 0.0f) {
     357         210 :                 float value = (height - _realFlexibleMinHeight) / (getCurrentFlexibleMax() - _realFlexibleMinHeight);
     358         210 :                 setFlexibleLevel(value);
     359             :         } else {
     360           0 :                 setFlexibleLevel(1.0f);
     361             :         }
     362         210 : }
     363             : 
     364           0 : void FlexibleLayout::setBaseNodePadding(float val) {
     365           0 :         if (_baseNodePadding != val) {
     366           0 :                 _baseNodePadding = val;
     367           0 :                 _contentSizeDirty = true;
     368             :         }
     369           0 : }
     370           0 : float FlexibleLayout::getBaseNodePadding() const {
     371           0 :         return _baseNodePadding;
     372             : }
     373             : 
     374         292 : float FlexibleLayout::getCurrentFlexibleHeight() const {
     375         292 :         return (getCurrentFlexibleMax() - _realFlexibleMinHeight) * _flexibleLevel + _realFlexibleMinHeight;
     376             : }
     377             : 
     378         784 : float FlexibleLayout::getCurrentFlexibleMax() const {
     379         784 :         return _realFlexibleMaxHeight + (((_viewDecoration & ViewDecorationFlags::Tracked) != ViewDecorationFlags::None)?_decorationPadding.top:0);
     380             : }
     381             : 
     382          52 : void FlexibleLayout::onPush(SceneContent2d *l, bool replace) {
     383          52 :         DecoratedLayout::onPush(l, replace);
     384             : 
     385          52 :         if (_appBar && !replace) {
     386          10 :                 if (auto prev = l->getPrevLayout()) {
     387          10 :                         auto nav = _appBar->getNavNode();
     388             : 
     389          10 :                         if (auto prevL = dynamic_cast<FlexibleLayout *>(prev)) {
     390          10 :                                 if (auto prevBar = prevL->getAppBar()) {
     391           0 :                                         if (prevBar->getNavButtonIcon() == IconName::Dynamic_Nav && _appBar->getNavButtonIcon() == IconName::Dynamic_Nav) {
     392           0 :                                                 auto p = prevBar->getNavNode()->getLeadingIconProgress();
     393           0 :                                                 if (p >= 1.0f) {
     394           0 :                                                         nav->setLeadingIconProgress(1.0f);
     395           0 :                                                 } else if (p < 1.0f) {
     396           0 :                                                         nav->setLeadingIconProgress(1.0f, 0.25f);
     397             :                                                 }
     398           0 :                                                 if (!_appBar->getNavCallback()) {
     399           0 :                                                         _appBar->setNavCallback([this] {
     400           0 :                                                                 onBackButton();
     401           0 :                                                         });
     402             :                                                 }
     403             :                                         }
     404           0 :                                         return;
     405             :                                 }
     406             :                         }
     407             : 
     408          10 :                         if (_appBar->getNavButtonIcon() == IconName::Dynamic_Nav) {
     409           0 :                                 _appBar->getNavNode()->setLeadingIconProgress(1.0f, 0.25f);
     410           0 :                                 if (!_appBar->getNavCallback()) {
     411           0 :                                         _appBar->setNavCallback([this] {
     412           0 :                                                 onBackButton();
     413           0 :                                         });
     414             :                                 }
     415             :                         }
     416             :                 }
     417             :         }
     418             : }
     419             : 
     420           0 : void FlexibleLayout::onForegroundTransitionBegan(SceneContent2d *l, SceneLayout2d *overlay) {
     421           0 :         DecoratedLayout::onForegroundTransitionBegan(l, overlay);
     422             : 
     423           0 :         if (_appBar) {
     424           0 :                 if (auto overlayL = dynamic_cast<FlexibleLayout *>(overlay)) {
     425           0 :                         if (auto overlayBar = overlayL->getAppBar()) {
     426           0 :                                 if (overlayBar->getNavButtonIcon() == IconName::Dynamic_Nav && _appBar->getNavButtonIcon() == IconName::Dynamic_Nav) {
     427           0 :                                         auto p = overlayBar->getNavNode()->getLeadingIconProgress();
     428           0 :                                         if (l->getPrevLayout() == nullptr) {
     429           0 :                                                 auto nav = _appBar->getNavNode();
     430           0 :                                                 nav->setLeadingIconProgress(p);
     431           0 :                                                 nav->setLeadingIconProgress(0.0f, 0.25f);
     432             :                                         }
     433             :                                 }
     434             :                         }
     435             :                 }
     436             :         }
     437           0 : }
     438             : 
     439          72 : void FlexibleLayout::onDecorNode(const NodeParams &p) {
     440          72 :         p.apply(_decorationTop);
     441          72 : }
     442             : 
     443          72 : void FlexibleLayout::onFlexibleNode(const NodeParams &p) {
     444          72 :         if (_flexibleNode) {
     445          30 :                 p.apply(_flexibleNode);
     446             :         }
     447          72 : }
     448             : 
     449          72 : void FlexibleLayout::onBaseNode(const NodeParams &p, const Padding &padding, float offset) {
     450          72 :         if (_baseNode) {
     451          30 :                 p.apply(_baseNode);
     452          30 :                 if (_baseNode->isVertical()) {
     453          30 :                         _baseNode->setOverscrollFrontOffset(offset);
     454          30 :                         _baseNode->setPadding(padding);
     455             :                 }
     456             :         }
     457          72 : }
     458             : 
     459           0 : void FlexibleLayout::setSafeTrigger(bool value) {
     460           0 :         _safeTrigger = value;
     461           0 : }
     462             : 
     463           0 : bool FlexibleLayout::isSafeTrigger() const {
     464           0 :         return _safeTrigger;
     465             : }
     466             : 
     467           0 : void FlexibleLayout::expandFlexibleNode(float extraSpace, float duration) {
     468           0 :         stopActionByTag("FlexibleExtraSpace"_tag);
     469           0 :         stopActionByTag("FlexibleExtraClear"_tag);
     470           0 :         if (duration > 0.0f) {
     471           0 :                 auto prevSpace = _flexibleExtraSpace;
     472           0 :                 if (extraSpace > prevSpace) {
     473           0 :                         auto a = makeEasing(Rc<ActionProgress>::create(
     474           0 :                                         duration, [this, extraSpace, prevSpace] (float p) {
     475           0 :                                 _flexibleExtraSpace = progress(prevSpace, extraSpace, p);
     476           0 :                                 updateFlexParams();
     477           0 :                         }), EasingType::Emphasized);
     478           0 :                         runAction(a, "FlexibleExtraSpace"_tag);
     479           0 :                 } else {
     480           0 :                         auto a = makeEasing(Rc<ActionProgress>::create(
     481           0 :                                         duration, [this, extraSpace, prevSpace] (float p) {
     482           0 :                                 _flexibleExtraSpace = progress(prevSpace, extraSpace, p);
     483           0 :                                 updateFlexParams();
     484           0 :                         }), EasingType::Emphasized);
     485           0 :                         runAction(a, "FlexibleExtraSpace"_tag);
     486           0 :                 }
     487             :         } else {
     488           0 :                 _flexibleExtraSpace = extraSpace;
     489           0 :                 updateFlexParams();
     490             :         }
     491           0 : }
     492             : 
     493         220 : void FlexibleLayout::clearFlexibleExpand(float duration) {
     494         220 :         if (_flexibleExtraSpace == 0.0f) {
     495         220 :                 return;
     496             :         }
     497             : 
     498           0 :         if (duration > 0.0f) {
     499           0 :                 auto a = getActionByTag("FlexibleExtraClear"_tag);
     500           0 :                 if (!a) {
     501           0 :                         stopActionByTag("FlexibleExtraSpace"_tag);
     502           0 :                         auto prevSpace = _flexibleExtraSpace;
     503           0 :                         auto a = makeEasing(Rc<ActionProgress>::create(
     504           0 :                                         duration, [this, prevSpace] (float p) {
     505           0 :                                 _flexibleExtraSpace = progress(prevSpace, 0.0f, p);
     506           0 :                                 updateFlexParams();
     507           0 :                         }), EasingType::Emphasized);
     508           0 :                         runAction(a, "FlexibleExtraClear"_tag);
     509           0 :                 }
     510             :         } else {
     511           0 :                 _flexibleExtraSpace = 0.0f;
     512           0 :                 updateFlexParams();
     513             :         }
     514             : }
     515             : 
     516          52 : DecorationStatus FlexibleLayout::getDecorationStatus() const {
     517          52 :         if ((_viewDecoration & ViewDecorationFlags::Visible) != ViewDecorationFlags::None) {
     518          52 :                 if ((_viewDecoration & ViewDecorationFlags::Tracked) != ViewDecorationFlags::None) {
     519           0 :                         return (_flexibleLevel == 1.0f) ? DecorationStatus::Visible : DecorationStatus::Hidden;
     520             :                 }
     521          52 :                 return DecorationStatus::Visible;
     522             :         } else {
     523           0 :                 return DecorationStatus::DontCare;
     524             :         }
     525             : }
     526             : 
     527             : }

Generated by: LCOV version 1.14