LCOV - code coverage report
Current view: top level - xenolith/scene/input - XLGestureRecognizer.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 14 14 100.0 %
Date: 2024-05-12 00:16:13 Functions: 24 24 100.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
       3             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       6             :  of this software and associated documentation files (the "Software"), to deal
       7             :  in the Software without restriction, including without limitation the rights
       8             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             :  copies of the Software, and to permit persons to whom the Software is
      10             :  furnished to do so, subject to the following conditions:
      11             : 
      12             :  The above copyright notice and this permission notice shall be included in
      13             :  all copies or substantial portions of the Software.
      14             : 
      15             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             :  THE SOFTWARE.
      22             :  **/
      23             : 
      24             : #ifndef XENOLITH_SCENE_INPUT_XLGESTURERECOGNIZER_H_
      25             : #define XENOLITH_SCENE_INPUT_XLGESTURERECOGNIZER_H_
      26             : 
      27             : #include "XLCommon.h"
      28             : #include "XLInput.h"
      29             : #include "SPMovingAverage.h"
      30             : 
      31             : namespace STAPPLER_VERSIONIZED stappler::xenolith {
      32             : 
      33             : static constexpr float TapDistanceAllowed = 12.0f;
      34             : static constexpr float TapDistanceAllowedMulti = 32.0f;
      35             : static constexpr TimeInterval TapIntervalAllowed = TimeInterval::microseconds(300000ULL);
      36             : 
      37             : class InputListener;
      38             : 
      39             : enum class GestureEvent {
      40             :         /** Action just started, listener should return true if it want to "capture" it.
      41             :          * Captured actions will be automatically propagated to end-listener
      42             :          * Other listeners branches will not recieve updates on action, that was not captured by them.
      43             :          * Only one listener on every level can capture action. If one of the listeners return 'true',
      44             :          * action will be captured by this listener, no other listener on this level can capture this action.
      45             :          */
      46             :         Began,
      47             : 
      48             :         /** Action was activated:
      49             :          * on Touch - touch was moved
      50             :          * on Tap - n-th  tap was recognized
      51             :          * on Press - long touch was recognized
      52             :          * on Swipe - touch was moved
      53             :          * on Pinch - any of two touches was moved, scale was changed
      54             :          * on Rotate - any of two touches was moved, rotation angle was changed
      55             :          */
      56             :         Activated,
      57             :         Moved = Activated,
      58             :         OnLongPress = Activated,
      59             :         Repeat = Activated,
      60             : 
      61             :         /** Action was successfully ended, no recognition errors was occurred */
      62             :         Ended,
      63             : 
      64             :         /** Action was not successfully ended, recognizer detects error in action
      65             :          * pattern and failed to continue recognition */
      66             :         Cancelled,
      67             : };
      68             : 
      69             : struct GestureData {
      70             :         GestureEvent event = GestureEvent::Began;
      71             :         const InputEvent *input = nullptr;
      72             : 
      73          96 :         Vec2 location() const { return input->currentLocation; }
      74         184 :         uint32_t getId() const { return input->data.id; }
      75             : };
      76             : 
      77             : struct GestureScroll : GestureData {
      78             :         Vec2 pos;
      79             :         Vec2 amount;
      80             : 
      81             :         const Vec2 &location() const;
      82             :         void cleanup();
      83             : };
      84             : 
      85             : struct GestureTap : GestureData {
      86             :         Vec2 pos;
      87             :         uint32_t id = maxOf<uint32_t>();
      88             :         uint32_t count = 0;
      89             :         Time time;
      90             : 
      91             :         void cleanup();
      92             : };
      93             : 
      94             : struct GesturePress : GestureData {
      95             :         Vec2 pos;
      96             :         uint32_t id = maxOf<uint32_t>();
      97             :         TimeInterval limit;
      98             :         TimeInterval time;
      99             :         uint32_t tickCount = 0;
     100             : 
     101             :     void cleanup();
     102             : };
     103             : 
     104             : struct GestureSwipe : GestureData {
     105             :         Vec2 firstTouch;
     106             :         Vec2 secondTouch;
     107             :         Vec2 midpoint;
     108             :         Vec2 delta;
     109             :         Vec2 velocity;
     110             :         float density = 1.0f;
     111             : 
     112             :     void cleanup();
     113             : };
     114             : 
     115             : struct GesturePinch : GestureData {
     116             :         Vec2 first;
     117             :         Vec2 second;
     118             :         Vec2 center;
     119             :         float startDistance = 0.0f;
     120             :         float prevDistance = 0.0f;
     121             :         float distance = 0.0f;
     122             :         float scale = 0.0f;
     123             :         float velocity = 0.0f;
     124             :         float density = 1.0f;
     125             : 
     126             :     void cleanup();
     127             : };
     128             : 
     129             : class GestureRecognizer : public Ref {
     130             : public:
     131             :         using EventMask = std::bitset<toInt(InputEventName::Max)>;
     132             :         using ButtonMask = std::bitset<toInt(InputMouseButton::Max)>;
     133             : 
     134        1166 :         virtual ~GestureRecognizer() { }
     135             : 
     136             :         virtual bool init();
     137             : 
     138             :         virtual bool canHandleEvent(const InputEvent &event) const;
     139             :         virtual InputEventState handleInputEvent(const InputEvent &, float density);
     140             : 
     141             :         virtual void onEnter(InputListener *);
     142             :         virtual void onExit();
     143             : 
     144             :         uint32_t getEventCount() const;
     145             :         bool hasEvent(const InputEvent &) const;
     146             : 
     147             :         EventMask getEventMask() const;
     148             : 
     149             :         virtual void update(uint64_t dt);
     150             :         virtual Vec2 getLocation() const;
     151             :         virtual void cancel();
     152             : 
     153          21 :         virtual void setMaxEvents(size_t value) { _maxEvents = value; }
     154          21 :         virtual size_t getMaxEvents() const { return _maxEvents; }
     155             : 
     156             : protected:
     157             :         virtual bool canAddEvent(const InputEvent &) const;
     158             :         virtual InputEventState addEvent(const InputEvent &, float density);
     159             :         virtual InputEventState removeEvent(const InputEvent &, bool success, float density);
     160             :         virtual InputEventState renewEvent(const InputEvent &, float density);
     161             : 
     162             :         virtual InputEvent *getTouchById(uint32_t id, uint32_t *index);
     163             : 
     164             :         Vector<InputEvent> _events;
     165             :         size_t _maxEvents = 0;
     166             :         EventMask _eventMask;
     167             :         ButtonMask _buttonMask;
     168             :         float _density = 1.0f;
     169             : };
     170             : 
     171             : class GestureTouchRecognizer : public GestureRecognizer {
     172             : public:
     173             :         using InputCallback = Function<bool(const GestureData &)>;
     174             : 
     175         302 :         virtual ~GestureTouchRecognizer() { }
     176             : 
     177             :         virtual bool init(InputCallback &&, ButtonMask &&);
     178             : 
     179             :         // disable touches if no button specified
     180             :         virtual bool canHandleEvent(const InputEvent &event) const override;
     181             : 
     182             :         void removeRecognizedEvent(uint32_t);
     183             : 
     184             : protected:
     185             :         using GestureRecognizer::init;
     186             : 
     187             :         virtual InputEventState addEvent(const InputEvent &, float density) override;
     188             :         virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
     189             :         virtual InputEventState renewEvent(const InputEvent &, float density) override;
     190             : 
     191             :         GestureData _event = GestureData{GestureEvent::Cancelled, nullptr};
     192             :         InputCallback _callback;
     193             : };
     194             : 
     195             : class GestureTapRecognizer : public GestureRecognizer {
     196             : public:
     197             :         using InputCallback = Function<void(const GestureTap &)>;
     198             :         using ButtonMask = std::bitset<toInt(InputMouseButton::Max)>;
     199             : 
     200        1452 :         virtual ~GestureTapRecognizer() { }
     201             : 
     202             :         virtual bool init(InputCallback &&, ButtonMask &&, uint32_t maxTapCount);
     203             : 
     204             :         virtual void update(uint64_t dt) override;
     205             :         virtual void cancel() override;
     206             : 
     207             : protected:
     208             :         using GestureRecognizer::init;
     209             : 
     210             :         virtual InputEventState addEvent(const InputEvent &, float density) override;
     211             :         virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
     212             :         virtual InputEventState renewEvent(const InputEvent &, float density) override;
     213             : 
     214             :         virtual void registerTap();
     215             : 
     216             :         GestureTap _gesture;
     217             :         InputCallback _callback;
     218             :         uint32_t _maxTapCount = 2;
     219             :         InputEvent _tmpEvent;
     220             : };
     221             : 
     222             : class GesturePressRecognizer : public GestureRecognizer {
     223             : public:
     224             :         using InputCallback = Function<bool(const GesturePress &)>;
     225             : 
     226        1116 :         virtual ~GesturePressRecognizer() { }
     227             : 
     228             :         virtual bool init(InputCallback &&, TimeInterval interval, bool continuous, ButtonMask &&);
     229             : 
     230             :         virtual void update(uint64_t dt) override;
     231             :         virtual void cancel() override;
     232             : 
     233             : protected:
     234             :         using GestureRecognizer::init;
     235             : 
     236             :         virtual InputEventState addEvent(const InputEvent &, float density) override;
     237             :         virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
     238             :         virtual InputEventState renewEvent(const InputEvent &, float density) override;
     239             : 
     240             :         Time _lastTime = Time::now();
     241             :         bool _notified = false;
     242             : 
     243             :         GesturePress _gesture;
     244             :         InputCallback _callback;
     245             : 
     246             :         TimeInterval _interval;
     247             :         bool _continuous = false;
     248             : };
     249             : 
     250             : class GestureSwipeRecognizer : public GestureRecognizer {
     251             : public:
     252             :         using InputCallback = Function<bool(const GestureSwipe &)>;
     253             : 
     254         348 :         virtual ~GestureSwipeRecognizer() { }
     255             : 
     256             :         virtual bool init(InputCallback &&, float threshold, bool includeThreshold, ButtonMask &&);
     257             : 
     258             :         virtual void cancel() override;
     259             : 
     260             : protected:
     261             :         using GestureRecognizer::init;
     262             : 
     263             :         virtual InputEventState addEvent(const InputEvent &, float density) override;
     264             :         virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
     265             :         virtual InputEventState renewEvent(const InputEvent &, float density) override;
     266             : 
     267             :         Time _lastTime;
     268             :         math::MovingAverage<4> _velocityX, _velocityY;
     269             : 
     270             :         bool _swipeBegin = false;
     271             :         uint32_t _currentTouch = maxOf<uint32_t>();
     272             : 
     273             :         GestureSwipe _gesture;
     274             :         InputCallback _callback;
     275             : 
     276             :         float _threshold = 6.0f;
     277             :         bool _includeThreshold = true;
     278             : };
     279             : 
     280             : class GesturePinchRecognizer : public GestureRecognizer {
     281             : public:
     282             :         using InputCallback = Function<void(const GesturePinch &)>;
     283             : 
     284          84 :         virtual ~GesturePinchRecognizer() { }
     285             : 
     286             :         virtual bool init(InputCallback &&, ButtonMask &&);
     287             : 
     288             :         virtual void cancel() override;
     289             : 
     290             : protected:
     291             :         using GestureRecognizer::init;
     292             : 
     293             :         virtual InputEventState addEvent(const InputEvent &, float density) override;
     294             :         virtual InputEventState removeEvent(const InputEvent &, bool successful, float density) override;
     295             :         virtual InputEventState renewEvent(const InputEvent &, float density) override;
     296             : 
     297             :         Time _lastTime;
     298             :         math::MovingAverage<3> _velocity;
     299             : 
     300             :         GesturePinch _gesture;
     301             :         InputCallback _callback;
     302             : };
     303             : 
     304             : class GestureScrollRecognizer : public GestureRecognizer {
     305             : public:
     306             :         using InputCallback = Function<bool(const GestureScroll &)>;
     307             : 
     308         264 :         virtual ~GestureScrollRecognizer() { }
     309             : 
     310             :         virtual bool init(InputCallback &&);
     311             : 
     312             :         virtual InputEventState handleInputEvent(const InputEvent &, float density) override;
     313             : 
     314             : protected:
     315             :         using GestureRecognizer::init;
     316             : 
     317             :         GestureScroll _gesture;
     318             :         InputCallback _callback;
     319             : };
     320             : 
     321             : class GestureMoveRecognizer : public GestureRecognizer {
     322             : public:
     323             :         using InputCallback = Function<bool(const GestureData &)>;
     324             : 
     325          84 :         virtual ~GestureMoveRecognizer() { }
     326             : 
     327             :         virtual bool init(InputCallback &&, bool withinNode);
     328             : 
     329             :         virtual bool canHandleEvent(const InputEvent &event) const override;
     330             :         virtual InputEventState handleInputEvent(const InputEvent &, float density) override;
     331             : 
     332             :         virtual void onEnter(InputListener *) override;
     333             :         virtual void onExit() override;
     334             : 
     335             : protected:
     336             :         using GestureRecognizer::init;
     337             : 
     338             :         GestureData _event = GestureData{GestureEvent::Cancelled, nullptr};
     339             :         InputCallback _callback;
     340             :         InputListener *_listener = nullptr;
     341             :         bool _onlyWithinNode = true;
     342             : };
     343             : 
     344             : class GestureKeyRecognizer : public GestureRecognizer {
     345             : public:
     346             :         using InputCallback = Function<bool(const GestureData &)>;
     347             :         using KeyMask = std::bitset<toInt(InputKeyCode::Max)>;
     348             : 
     349         168 :         virtual ~GestureKeyRecognizer() { }
     350             : 
     351             :         virtual bool init(InputCallback &&, KeyMask &&);
     352             : 
     353             :         virtual bool canHandleEvent(const InputEvent &) const override;
     354             : 
     355             :         bool isKeyPressed(InputKeyCode) const;
     356             : 
     357             : protected:
     358             :         using GestureRecognizer::init;
     359             : 
     360             :         virtual InputEventState addEvent(const InputEvent &, float density) override;
     361             :         virtual InputEventState removeEvent(const InputEvent &, bool success, float density) override;
     362             :         virtual InputEventState renewEvent(const InputEvent &, float density) override;
     363             : 
     364             :         KeyMask _keyMask;
     365             :         KeyMask _pressedKeys;
     366             :         InputCallback _callback;
     367             : };
     368             : 
     369             : class GestureMouseOverRecognizer : public GestureRecognizer {
     370             : public:
     371             :         using InputCallback = Function<bool(const GestureData &)>;
     372             : 
     373         894 :         virtual ~GestureMouseOverRecognizer() { }
     374             : 
     375             :         virtual bool init(InputCallback &&, float padding = 0.0f);
     376             : 
     377             :         virtual InputEventState handleInputEvent(const InputEvent &, float density) override;
     378             : 
     379             :         virtual void onEnter(InputListener *) override;
     380             :         virtual void onExit() override;
     381             : 
     382             : protected:
     383             :         using GestureRecognizer::init;
     384             : 
     385             :         void updateState(const InputEvent &);
     386             : 
     387             :         GestureData _event = GestureData{GestureEvent::Cancelled, nullptr};
     388             :         bool _viewHasPointer = false;
     389             :         bool _viewHasFocus = false;
     390             :         bool _hasMouseOver = false;
     391             :         bool _value = false;
     392             :         float _padding = 0.0f;
     393             :         InputCallback _callback;
     394             :         InputListener *_listener = nullptr;
     395             : };
     396             : 
     397             : std::ostream &operator<<(std::ostream &, GestureEvent);
     398             : 
     399             : }
     400             : 
     401             : #endif /* XENOLITH_SCENE_INPUT_XLGESTURERECOGNIZER_H_ */

Generated by: LCOV version 1.14