File indexing completed on 2025-07-13 05:03:00

0001 // SPDX-FileCopyrightText: 2023 Devin Lin <espidev@gmail.com>
0002 // SPDX-License-Identifier: LGPL-2.0-or-later
0003 
0004 #pragma once
0005 
0006 #include <QMouseEvent>
0007 #include <QPointF>
0008 #include <QPointerEvent>
0009 #include <QQmlListProperty>
0010 #include <QQuickItem>
0011 #include <QTouchEvent>
0012 
0013 /**
0014  * @short A component that provides access to swipes over its children, similar to Flickable.
0015  * However, it does not do any of the positioning Flickable does, and so it
0016  * can be used to build custom components with specialized swiping needs (ex. panels)
0017  *
0018  * TODO: New fingers that come in should steal from the old finger
0019  *
0020  * @author Devin Lin <devin@kde.org>
0021  */
0022 class SwipeArea : public QQuickItem
0023 {
0024     Q_OBJECT
0025     QML_ELEMENT
0026     Q_PROPERTY(SwipeArea::Mode mode READ mode WRITE setMode NOTIFY modeChanged)
0027     Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged)
0028     Q_PROPERTY(bool moving READ moving NOTIFY movingChanged)
0029     Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
0030 
0031 public:
0032     SwipeArea(QQuickItem *parent = nullptr);
0033 
0034     enum Mode { BothAxis = 0, VerticalOnly, HorizontalOnly };
0035     Q_ENUM(Mode)
0036 
0037     Mode mode() const;
0038     void setMode(Mode mode);
0039 
0040     bool interactive() const;
0041     void setInteractive(bool interactive);
0042 
0043     bool moving() const;
0044     bool pressed() const;
0045 
0046     Q_INVOKABLE void setSkipSwipeThreshold(bool value);
0047 
0048 Q_SIGNALS:
0049     void modeChanged();
0050     void interactiveChanged();
0051     void movingChanged();
0052     void pressedChanged();
0053 
0054     void swipeEnded();
0055     void swipeStarted(QPointF point);
0056 
0057     // deltaX, deltaY - amount moved since last swipeMove()
0058     // totalDeltaX, totalDeltaY - amount move since startedSwipe()
0059     void swipeMove(qreal totalDeltaX, qreal totalDeltaY, qreal deltaX, qreal deltaY);
0060 
0061 protected:
0062     bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
0063     void mouseMoveEvent(QMouseEvent *event) override;
0064     void mousePressEvent(QMouseEvent *event) override;
0065     void mouseReleaseEvent(QMouseEvent *event) override;
0066     void mouseUngrabEvent() override;
0067     void touchEvent(QTouchEvent *event) override;
0068     void touchUngrabEvent() override;
0069 
0070 private:
0071     void setMoving(bool moving);
0072     void setPressed(bool pressed);
0073 
0074     bool filterPointerEvent(QQuickItem *receiver, QPointerEvent *event);
0075 
0076     void handlePressEvent(QPointerEvent *event, QPointF point);
0077     void handleReleaseEvent(QPointerEvent *event, QPointF point);
0078     void handleMoveEvent(QPointerEvent *event, QPointF point);
0079 
0080     void resetSwipe();
0081 
0082     Mode m_mode = Mode::BothAxis;
0083     bool m_interactive = true;
0084     bool m_pressed = false;
0085 
0086     // whether we have started a flick
0087     bool m_moving = false;
0088 
0089     // whether on this current flick, we want to steal the mouse/touch event from children
0090     bool m_stealMouse = false;
0091 
0092     // the point where the user pressed down on at the start of the interaction
0093     QPointF m_pressPos;
0094 
0095     // the point where the swipe actually started being registered (can be some distance from the pressed position)
0096     QPointF m_startPos;
0097 
0098     // the previous point where interaction was at
0099     QPointF m_lastPos;
0100 
0101     // whether to skip trying to measure the swipe threshold
0102     bool m_skipSwipeThreshold;
0103 };
0104 
0105 QML_DECLARE_TYPE(SwipeArea)