LCOV - code coverage report
Current view: top level - xenolith/renderer/material2d/layout - MaterialSceneContent.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 93 162 57.4 %
Date: 2024-05-12 00:16:13 Functions: 16 32 50.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 "MaterialSceneContent.h"
      24             : #include "MaterialLabel.h"
      25             : #include "MaterialButton.h"
      26             : #include "MaterialEasing.h"
      27             : #include "MaterialNavigationDrawer.h"
      28             : #include "XLInputListener.h"
      29             : #include "XLAction.h"
      30             : 
      31             : namespace STAPPLER_VERSIONIZED stappler::xenolith::material2d {
      32             : 
      33             : class Snackbar : public Node {
      34             : public:
      35          20 :         virtual ~Snackbar() { }
      36             : 
      37             :         virtual bool init() override;
      38             :         virtual void onContentSizeDirty() override;
      39             : 
      40             :         virtual void setSnackbarData(SnackbarData &&);
      41             : 
      42             :         const SnackbarData &getData() const;
      43             : 
      44             :         void clear();
      45             : 
      46             :         void hide(Function<void()> &&cb);
      47             :         void show(SnackbarData &&);
      48             : 
      49             :         void onHidden();
      50             :         void onButton();
      51             : 
      52             : protected:
      53             :         SnackbarData _data;
      54             :         Surface *_surface = nullptr;
      55             :         TypescaleLabel *_label = nullptr;
      56             :         Button *_button = nullptr;
      57             :         InputListener *_listener = nullptr;
      58             :         bool _scheduledUpdate = false;
      59             : };
      60             : 
      61          10 : bool Snackbar::init() {
      62          10 :         if (!Node::init()) {
      63           0 :                 return false;
      64             :         }
      65             : 
      66          10 :         setAnchorPoint(Anchor::MiddleBottom);
      67             : 
      68          10 :         _listener = addInputListener(Rc<InputListener>::create());
      69          10 :         _listener->addTouchRecognizer([this] (const GestureData &data) -> bool {
      70           0 :                 if (data.event == GestureEvent::Began) {
      71           0 :                         stopAllActions();
      72           0 :                         runAction(Rc<Sequence>::create(_data.delayTime, std::bind(&Snackbar::hide, this, nullptr)));
      73             :                 }
      74           0 :                 return true;
      75             :         });
      76          10 :         _listener->setSwallowEvents(InputListener::EventMaskTouch);
      77             : 
      78          10 :         _surface = addChild(Rc<Surface>::create(SurfaceStyle(NodeStyle::Filled, Elevation::Level5, ColorRole::OnSurfaceVariant)));
      79             : 
      80          10 :         _label = _surface->addChild(Rc<TypescaleLabel>::create(TypescaleRole::BodyLarge), ZOrder(1));
      81          10 :         _label->setLocaleEnabled(true);
      82          10 :         _label->setAnchorPoint(Anchor::MiddleLeft);
      83             : 
      84          10 :         _button = _surface->addChild(Rc<Button>::create(NodeStyle::Text), ZOrder(1));
      85          10 :         _button->setTapCallback([this] {
      86           0 :                 onButton();
      87           0 :         });
      88          10 :         _button->setAnchorPoint(Anchor::MiddleRight);
      89          10 :         _button->setVisible(false);
      90          10 :         _button->setSwallowEvents(true);
      91             : 
      92          10 :         return true;
      93             : }
      94             : 
      95           0 : void Snackbar::onContentSizeDirty() {
      96           0 :         Node::onContentSizeDirty();
      97             : 
      98           0 :         _surface->setContentSize(_contentSize);
      99             : 
     100           0 :         _button->setPosition(Vec2(_contentSize.width - 8.0f, _contentSize.height / 2.0f));
     101           0 :         _button->setContentSize(Size2(_button->getContentSize().width, _contentSize.height));
     102             : 
     103           0 :         _label->setPosition(Vec2(24.0f, _contentSize.height / 2.0f));
     104           0 : }
     105             : 
     106          10 : void Snackbar::setSnackbarData(SnackbarData &&data) {
     107          10 :         _data = move(data);
     108             : 
     109          10 :         if (!_data.buttonText.empty() && _data.buttonCallback) {
     110          10 :                 _button->setVisible(true);
     111          10 :                 _button->setLeadingIconName(_data.buttonIcon);
     112          10 :                 _button->setText(string::toupper<Interface>(_data.buttonText));
     113          10 :                 _button->setBlendColor(_data.buttonColor, _data.buttonBlendValue);
     114          10 :                 _label->setWidth(_contentSize.width - 48.0f - _button->getContentSize().width);
     115             :         } else {
     116           0 :                 _button->setVisible(false);
     117           0 :                 _label->setWidth(_contentSize.width - 48.0f);
     118             :         }
     119             : 
     120          10 :         _label->setString(_data.text);
     121          10 :         _label->setBlendColor(_data.textColor, _data.textBlendValue);
     122          10 :         _label->tryUpdateLabel();
     123             : 
     124          10 :         setContentSize(Size2(_contentSize.width, _label->getContentSize().height + 32.0f));
     125          10 :         setPosition(Vec2(_position.x, -_contentSize.height));
     126          10 :         if (!_data.text.empty() || !_data.buttonText.empty()) {
     127          10 :                 setVisible(true);
     128          10 :                 setOpacity(1.0f);
     129          10 :                 runAction(Rc<Sequence>::create(makeEasing(Rc<MoveTo>::create(0.25f, Vec2(_position.x, 0)), EasingType::Standard), _data.delayTime,
     130          20 :                                 std::bind(&Snackbar::hide, this, nullptr)));
     131             :         }
     132          10 : }
     133             : 
     134           0 : const SnackbarData &Snackbar::getData() const {
     135           0 :         return _data;
     136             : }
     137             : 
     138           0 : void Snackbar::clear() {
     139           0 :         setSnackbarData(SnackbarData(""));
     140           0 : }
     141             : 
     142           0 : void Snackbar::hide(Function<void()> &&cb) {
     143           0 :         if (!cb) {
     144           0 :                 runAction(Rc<Sequence>::create(
     145           0 :                                 makeEasing(Rc<MoveTo>::create(0.25f, Vec2(_position.x, -_contentSize.height)), EasingType::Standard),
     146           0 :                                 std::bind(&Snackbar::onHidden, this)));
     147             :         } else {
     148           0 :                 runAction(Rc<Sequence>::create(
     149           0 :                                 makeEasing(Rc<MoveTo>::create(0.25f, Vec2(_position.x, -_contentSize.height)), EasingType::Standard),
     150           0 :                                 move(cb)));
     151             :         }
     152           0 : }
     153             : 
     154          10 : void Snackbar::show(SnackbarData &&data) {
     155          10 :         stopAllActions();
     156          10 :         if (!isVisible()) {
     157          10 :                 setSnackbarData(move(data));
     158             :         } else {
     159           0 :                 _scheduledUpdate = true;
     160           0 :                 hide([this, data = move(data)] {
     161           0 :                         _scheduledUpdate = false;
     162           0 :                         setSnackbarData(move(const_cast<SnackbarData &>(data)));
     163           0 :                 });
     164             :         }
     165          10 : }
     166             : 
     167          20 : void Snackbar::onHidden() {
     168          20 :         stopAllActions();
     169          20 :         setVisible(false);
     170          20 :         setPosition(Vec2(_position.x, -_contentSize.height));
     171          20 :         _button->setVisible(false);
     172          20 :         _label->setString("");
     173          20 : }
     174             : 
     175           0 : void Snackbar::onButton() {
     176           0 :         if (_data.buttonCallback) {
     177           0 :                 _data.buttonCallback();
     178           0 :                 _data.buttonCallback = nullptr;
     179             :         }
     180           0 :         if (!_scheduledUpdate) {
     181           0 :                 stopAllActions();
     182           0 :                 runAction(Rc<Sequence>::create(0.35f, std::bind(&Snackbar::hide, this, nullptr)));
     183             :         }
     184           0 : }
     185             : 
     186             : 
     187          20 : SceneContent::~SceneContent() { }
     188             : 
     189          10 : bool SceneContent::init() {
     190          10 :         if (!SceneContent2d::init()) {
     191           0 :                 return false;
     192             :         }
     193             : 
     194          10 :         _snackbarRoot = addChild(Rc<Node>::create());
     195             : 
     196          10 :         _snackbar = _snackbarRoot->addChild(Rc<Snackbar>::create(), ZOrderMax - ZOrder(2));
     197          10 :         _snackbar->setVisible(false);
     198             : 
     199          10 :         _navigation = addChild(Rc<NavigationDrawer>::create(), ZOrderMax - ZOrder(3));
     200             : 
     201          10 :         return true;
     202             : }
     203             : 
     204          20 : void SceneContent::onContentSizeDirty() {
     205          20 :         SceneContent2d::onContentSizeDirty();
     206             : 
     207          20 :         _snackbarRoot->setPosition(Vec2::ZERO);
     208          20 :         _snackbarRoot->setContentSize(_contentSize);
     209             : 
     210          20 :         _snackbar->onHidden();
     211          20 :         _snackbar->setContentSize(Size2(std::min(_contentSize.width, 536.0f), 48.0f));
     212          20 :         _snackbar->setPosition(Vec2(_contentSize.width / 2, -48.0f));
     213             : 
     214          20 :         _navigation->setPosition(Vec2::ZERO);
     215          20 :         _navigation->setContentSize(_contentSize);
     216          20 : }
     217             : 
     218        4650 : bool SceneContent::visitDraw(FrameInfo &frame, NodeFlags parentFlags) {
     219        4650 :         if (!_visible) {
     220           0 :                 return false;
     221             :         }
     222             : 
     223        4650 :         auto maxDepth = getMaxDepthIndex();
     224             : 
     225        4650 :         _snackbar->setDepthIndex(maxDepth);
     226        4650 :         _navigation->setDepthIndex(maxDepth);
     227             : 
     228        4650 :         return SceneContent2d::visitDraw(frame, parentFlags);
     229             : }
     230             : 
     231          10 : void SceneContent::showSnackbar(SnackbarData &&data) {
     232          10 :         _snackbar->show(move(data));
     233          10 : }
     234           0 : const String &SceneContent::getSnackbarString() const {
     235           0 :         return _snackbar->getData().text;
     236             : }
     237           0 : void SceneContent::clearSnackbar() {
     238           0 :         _snackbar->clear();
     239           0 : }
     240             : 
     241           0 : bool SceneContent::isNavigationAvailable() const {
     242           0 :         return _navigation->isEnabled();
     243             : }
     244             : 
     245           0 : void SceneContent::setNavigationEnabled(bool value) {
     246           0 :         _navigation->setEnabled(value);
     247           0 : }
     248             : 
     249           0 : void SceneContent::setNavigationMenuSource(MenuSource *source) {
     250           0 :         _navigation->setMenuSource(source);
     251           0 : }
     252             : 
     253           0 : void SceneContent::setNavigationStyle(const SurfaceStyle &style) {
     254           0 :         _navigation->setStyle(style);
     255           0 : }
     256             : 
     257           0 : void SceneContent::openNavigation() {
     258           0 :         _navigation->show();
     259           0 : }
     260             : 
     261           0 : void SceneContent::closeNavigation() {
     262           0 :         _navigation->hide();
     263           0 : }
     264             : 
     265        4650 : float SceneContent::getMaxDepthIndex() const {
     266        4650 :         float maxIndex = _depthIndex;
     267       65523 :         for (auto &it : _children) {
     268       60873 :                 if (it != _snackbar && it != _snackbar && it->isVisible()) {
     269       18600 :                         maxIndex = std::max(it->getMaxDepthIndex(), maxIndex);
     270             :                 }
     271             :         }
     272        4650 :         return maxIndex;
     273             : }
     274             : 
     275          10 : bool SceneContent::onBackButton() {
     276          10 :         if (_navigation->isNodeVisible()) {
     277           0 :                 _navigation->hide();
     278           0 :                 return true;
     279             :         }
     280          10 :         return SceneContent2d::onBackButton();
     281             : }
     282             : 
     283         146 : void SceneContent::updateNodesVisibility() {
     284         146 :         SceneContent2d::updateNodesVisibility();
     285             : 
     286         146 :         if (!_layouts.empty()) {
     287         146 :                 _snackbarRoot->setLocalZOrder(_layouts.back()->getLocalZOrder());
     288             :         }
     289         146 : }
     290             : 
     291          20 : void SceneContent::handleBackgroundTransition(bool value) {
     292          20 :         SceneContent2d::handleBackgroundTransition(value);
     293             : 
     294          20 :         _contentSizeDirty = true;
     295          20 : }
     296             : 
     297             : }

Generated by: LCOV version 1.14