File indexing completed on 2024-05-12 05:37:14

0001 /*
0002     SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QPointer>
0010 #include <QQmlParserStatus>
0011 #include <QQuickItem>
0012 
0013 #include "appletslayout.h"
0014 
0015 class QTimer;
0016 
0017 class ConfigOverlay;
0018 
0019 class ItemContainer : public QQuickItem
0020 {
0021     Q_OBJECT
0022     Q_INTERFACES(QQmlParserStatus)
0023 
0024     Q_PROPERTY(AppletsLayout *layout READ layout NOTIFY layoutChanged)
0025     // TODO: make it unchangeable? probably not
0026     Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged)
0027     Q_PROPERTY(ItemContainer::EditModeCondition editModeCondition READ editModeCondition WRITE setEditModeCondition NOTIFY editModeConditionChanged)
0028     Q_PROPERTY(bool editMode READ editMode WRITE setEditMode NOTIFY editModeChanged)
0029     Q_PROPERTY(bool dragActive READ dragActive NOTIFY dragActiveChanged)
0030     Q_PROPERTY(AppletsLayout::PreferredLayoutDirection preferredLayoutDirection READ preferredLayoutDirection WRITE setPreferredLayoutDirection NOTIFY
0031                    preferredLayoutDirectionChanged)
0032 
0033     Q_PROPERTY(QUrl configOverlaySource READ configOverlaySource WRITE setConfigOverlaySource NOTIFY configOverlaySourceChanged)
0034     Q_PROPERTY(bool configOverlayVisible READ configOverlayVisible WRITE setConfigOverlayVisible NOTIFY configOverlayVisibleChanged)
0035     Q_PROPERTY(QQuickItem *configOverlayItem READ configOverlayItem NOTIFY configOverlayItemChanged)
0036 
0037     /**
0038      * Initial size this container asks to have upon creation. only positive values are considered
0039      */
0040     Q_PROPERTY(QSizeF initialSize READ initialSize WRITE setInitialSize NOTIFY initialSizeChanged)
0041     // From there mostly a clone of QQC2 Control
0042     Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged)
0043     Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged)
0044 
0045     /**
0046      * Padding adds a space between each edge of the content item and the background item, effectively controlling the size of the content item.
0047      */
0048     Q_PROPERTY(int leftPadding READ leftPadding WRITE setLeftPadding NOTIFY leftPaddingChanged)
0049     Q_PROPERTY(int rightPadding READ rightPadding WRITE setRightPadding NOTIFY rightPaddingChanged)
0050     Q_PROPERTY(int topPadding READ topPadding WRITE setTopPadding NOTIFY topPaddingChanged)
0051     Q_PROPERTY(int bottomPadding READ bottomPadding WRITE setBottomPadding NOTIFY bottomPaddingChanged)
0052 
0053     /**
0054      * The size of the contents: the size of this item minus the padding
0055      */
0056     Q_PROPERTY(int contentWidth READ contentWidth NOTIFY contentWidthChanged)
0057     Q_PROPERTY(int contentHeight READ contentHeight NOTIFY contentHeightChanged)
0058 
0059     Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL)
0060     // Q_CLASSINFO("DeferredPropertyNames", "background,contentItem")
0061     Q_CLASSINFO("DefaultProperty", "contentData")
0062 
0063 public:
0064     enum EditModeCondition {
0065         Locked = AppletsLayout::EditModeCondition::Locked,
0066         Manual = AppletsLayout::EditModeCondition::Manual,
0067         AfterPressAndHold = AppletsLayout::EditModeCondition::AfterPressAndHold,
0068         AfterPress,
0069         AfterMouseOver,
0070     };
0071     Q_ENUMS(EditModeCondition)
0072 
0073     ItemContainer(QQuickItem *parent = nullptr);
0074     ~ItemContainer();
0075 
0076     QQmlListProperty<QObject> contentData();
0077 
0078     QString key() const;
0079     void setKey(const QString &id);
0080 
0081     bool editMode() const;
0082     void setEditMode(bool edit);
0083 
0084     bool dragActive() const;
0085 
0086     Q_INVOKABLE void cancelEdit();
0087 
0088     EditModeCondition editModeCondition() const;
0089     void setEditModeCondition(EditModeCondition condition);
0090 
0091     AppletsLayout::PreferredLayoutDirection preferredLayoutDirection() const;
0092     void setPreferredLayoutDirection(AppletsLayout::PreferredLayoutDirection direction);
0093 
0094     QUrl configOverlaySource() const;
0095     void setConfigOverlaySource(const QUrl &url);
0096 
0097     bool configOverlayVisible() const;
0098     void setConfigOverlayVisible(bool visible);
0099 
0100     // TODO: keep this accessible?
0101     ConfigOverlay *configOverlayItem() const;
0102 
0103     QSizeF initialSize() const;
0104     void setInitialSize(const QSizeF &size);
0105 
0106     // Control-like api
0107     QQuickItem *contentItem() const;
0108     void setContentItem(QQuickItem *item);
0109 
0110     QQuickItem *background() const;
0111     void setBackground(QQuickItem *item);
0112 
0113     // Setters and getters for the padding
0114     int leftPadding() const;
0115     void setLeftPadding(int padding);
0116 
0117     int topPadding() const;
0118     void setTopPadding(int padding);
0119 
0120     int rightPadding() const;
0121     void setRightPadding(int padding);
0122 
0123     int bottomPadding() const;
0124     void setBottomPadding(int padding);
0125 
0126     int contentWidth() const;
0127     int contentHeight() const;
0128 
0129     AppletsLayout *layout() const;
0130 
0131     // Not for QML
0132     void setLayout(AppletsLayout *layout);
0133 
0134     QObject *layoutAttached() const
0135     {
0136         return m_layoutAttached;
0137     }
0138 
0139 protected:
0140     void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0141 
0142     // void classBegin() override;
0143     void componentComplete() override;
0144     bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
0145     void mousePressEvent(QMouseEvent *event) override;
0146     void mouseReleaseEvent(QMouseEvent *event) override;
0147     void mouseMoveEvent(QMouseEvent *event) override;
0148     void mouseUngrabEvent() override;
0149     void hoverEnterEvent(QHoverEvent *event) override;
0150     void hoverLeaveEvent(QHoverEvent *event) override;
0151 
0152 Q_SIGNALS:
0153 
0154     /**
0155      * The user manually dragged the ItemContainer around
0156      * @param newPosition new position of the ItemContainer in parent coordinates
0157      * @param dragCenter position in ItemContainer coordinates of the drag hotspot, i.e. where the user pressed the mouse or the
0158      * finger over the ItemContainer
0159      */
0160     void userDrag(const QPointF &newPosition, const QPointF &dragCenter);
0161 
0162     void dragActiveChanged();
0163 
0164     /**
0165      * The attached layout object changed some of its size hints
0166      */
0167     void sizeHintsChanged();
0168 
0169     // QML property notifiers
0170     void layoutChanged();
0171     void keyChanged();
0172     void editModeConditionChanged();
0173     void editModeChanged(bool editMode);
0174     void preferredLayoutDirectionChanged();
0175     void configOverlaySourceChanged();
0176     void configOverlayItemChanged();
0177     void initialSizeChanged();
0178     void configOverlayVisibleChanged(bool configOverlayVisile);
0179 
0180     void backgroundChanged();
0181     void contentItemChanged();
0182     void leftPaddingChanged();
0183     void rightPaddingChanged();
0184     void topPaddingChanged();
0185     void bottomPaddingChanged();
0186     void contentWidthChanged();
0187     void contentHeightChanged();
0188 
0189 private Q_SLOTS:
0190     void onConfigOverlayComponentStatusChanged(QQmlComponent::Status status, QQmlComponent *component = nullptr);
0191 
0192 private:
0193     void syncChildItemsGeometry(const QSizeF &size);
0194     void sendUngrabRecursive(QQuickItem *item);
0195 
0196     void loadConfigOverlayItem();
0197 
0198     // internal accessorts for the contentData QProperty
0199     static void contentData_append(QQmlListProperty<QObject> *prop, QObject *object);
0200     static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
0201     static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
0202     static void contentData_clear(QQmlListProperty<QObject> *prop);
0203 
0204     QPointer<QQuickItem> m_contentItem;
0205     QPointer<QQuickItem> m_backgroundItem;
0206 
0207     // Internal implementation detail: this is used to reparent all items to contentItem
0208     QList<QObject *> m_contentData;
0209 
0210     /**
0211      * Padding adds a space between each edge of the content item and the background item, effectively controlling the size of the content item.
0212      */
0213     int m_leftPadding = 0;
0214     int m_rightPadding = 0;
0215     int m_topPadding = 0;
0216     int m_bottomPadding = 0;
0217 
0218     QString m_key;
0219 
0220     QPointer<AppletsLayout> m_layout;
0221     QTimer *m_editModeTimer = nullptr;
0222     QTimer *m_closeEditModeTimer = nullptr;
0223     QTimer *m_sizeHintAdjustTimer = nullptr;
0224     QObject *m_layoutAttached = nullptr;
0225     EditModeCondition m_editModeCondition = Manual;
0226     QSizeF m_initialSize;
0227 
0228     QUrl m_configOverlaySource;
0229     ConfigOverlay *m_configOverlay = nullptr;
0230     bool m_configOverlayVisible = false;
0231 
0232     QPointF m_lastMousePosition = QPoint(-1, -1);
0233     QPointF m_mouseDownPosition = QPoint(-1, -1);
0234     AppletsLayout::PreferredLayoutDirection m_preferredLayoutDirection = AppletsLayout::Closest;
0235     bool m_editMode = false;
0236     bool m_mouseDown = false;
0237     bool m_mouseSynthetizedFromTouch = false;
0238     bool m_dragActive = false;
0239 };