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

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 #include <QQuickWindow>
0013 
0014 class QTimer;
0015 
0016 namespace Plasma
0017 {
0018 class Applet;
0019 class Containment;
0020 }
0021 
0022 namespace PlasmaQuick
0023 {
0024 class AppletQuickItem;
0025 }
0026 
0027 class AbstractLayoutManager;
0028 class AppletContainer;
0029 class ItemContainer;
0030 
0031 class AppletsLayout : public QQuickItem
0032 {
0033     Q_OBJECT
0034     Q_INTERFACES(QQmlParserStatus)
0035 
0036     Q_PROPERTY(QString configKey READ configKey WRITE setConfigKey NOTIFY configKeyChanged)
0037 
0038     // A config key that can be used as fallback when loading and configKey is not found
0039     // Is always a backup of the last used configKey. Useful when the configkey depends
0040     // from the screen size and plasma starts on an "unexpected" size
0041     Q_PROPERTY(QString fallbackConfigKey READ fallbackConfigKey WRITE setFallbackConfigKey NOTIFY fallbackConfigKeyChanged)
0042 
0043     Q_PROPERTY(bool relayoutLock READ relayoutLock WRITE setRelayoutLock NOTIFY relayoutLockChanged)
0044 
0045     Q_PROPERTY(Plasma::Containment *containment READ containment WRITE setContainment NOTIFY containmentChanged)
0046 
0047     Q_PROPERTY(PlasmaQuick::AppletQuickItem *containmentItem READ containmentItem WRITE setContainmentItem NOTIFY containmentItemChanged)
0048 
0049     Q_PROPERTY(QJSValue acceptsAppletCallback READ acceptsAppletCallback WRITE setAcceptsAppletCallback NOTIFY acceptsAppletCallbackChanged)
0050 
0051     Q_PROPERTY(qreal minimumItemWidth READ minimumItemWidth WRITE setMinimumItemWidth NOTIFY minimumItemWidthChanged)
0052 
0053     Q_PROPERTY(qreal minimumItemHeight READ minimumItemHeight WRITE setMinimumItemHeight NOTIFY minimumItemHeightChanged)
0054 
0055     Q_PROPERTY(qreal defaultItemWidth READ defaultItemWidth WRITE setDefaultItemWidth NOTIFY defaultItemWidthChanged)
0056 
0057     Q_PROPERTY(qreal defaultItemHeight READ defaultItemHeight WRITE setDefaultItemHeight NOTIFY defaultItemHeightChanged)
0058 
0059     Q_PROPERTY(qreal cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged)
0060 
0061     Q_PROPERTY(qreal cellHeight READ cellHeight WRITE setCellHeight NOTIFY cellHeightChanged)
0062 
0063     Q_PROPERTY(QQmlComponent *appletContainerComponent READ appletContainerComponent WRITE setAppletContainerComponent NOTIFY appletContainerComponentChanged)
0064 
0065     Q_PROPERTY(ItemContainer *placeHolder READ placeHolder WRITE setPlaceHolder NOTIFY placeHolderChanged)
0066 
0067     /**
0068      * if the applets layout contains some kind of main MouseArea,
0069      * MouseEventListener or Flickable, we want to filter its events to make the
0070      * long mouse press work
0071      */
0072     Q_PROPERTY(QQuickItem *eventManagerToFilter READ eventManagerToFilter WRITE setEventManagerToFilter NOTIFY eventManagerToFilterChanged)
0073 
0074     Q_PROPERTY(AppletsLayout::EditModeCondition editModeCondition READ editModeCondition WRITE setEditModeCondition NOTIFY editModeConditionChanged)
0075     Q_PROPERTY(bool editMode READ editMode WRITE setEditMode NOTIFY editModeChanged)
0076 
0077 public:
0078     enum PreferredLayoutDirection {
0079         Closest = 0,
0080         LeftToRight,
0081         RightToLeft,
0082         TopToBottom,
0083         BottomToTop,
0084     };
0085     Q_ENUM(PreferredLayoutDirection)
0086 
0087     enum EditModeCondition {
0088         Locked = 0,
0089         Manual,
0090         AfterPressAndHold,
0091     };
0092     Q_ENUM(EditModeCondition)
0093 
0094     enum LayoutChange {
0095         NoChange = 0,
0096         SizeChange = 1,
0097         ConfigKeyChange = 2,
0098     };
0099     Q_DECLARE_FLAGS(LayoutChanges, LayoutChange)
0100 
0101     AppletsLayout(QQuickItem *parent = nullptr);
0102     ~AppletsLayout();
0103 
0104     // QML setters and getters
0105     QString configKey() const;
0106     void setConfigKey(const QString &key);
0107 
0108     QString fallbackConfigKey() const;
0109     void setFallbackConfigKey(const QString &key);
0110 
0111     bool relayoutLock() const;
0112     void setRelayoutLock(bool lock);
0113 
0114     Plasma::Containment *containment() const;
0115     void setContainment(Plasma::Containment *containment);
0116 
0117     PlasmaQuick::AppletQuickItem *containmentItem() const;
0118     void setContainmentItem(PlasmaQuick::AppletQuickItem *containment);
0119 
0120     QJSValue acceptsAppletCallback() const;
0121     void setAcceptsAppletCallback(const QJSValue &callback);
0122 
0123     qreal minimumItemWidth() const;
0124     void setMinimumItemWidth(qreal width);
0125 
0126     qreal minimumItemHeight() const;
0127     void setMinimumItemHeight(qreal height);
0128 
0129     qreal defaultItemWidth() const;
0130     void setDefaultItemWidth(qreal width);
0131 
0132     qreal defaultItemHeight() const;
0133     void setDefaultItemHeight(qreal height);
0134 
0135     qreal cellWidth() const;
0136     void setCellWidth(qreal width);
0137 
0138     qreal cellHeight() const;
0139     void setCellHeight(qreal height);
0140 
0141     QQmlComponent *appletContainerComponent() const;
0142     void setAppletContainerComponent(QQmlComponent *component);
0143 
0144     ItemContainer *placeHolder() const;
0145     void setPlaceHolder(ItemContainer *placeHolder);
0146 
0147     QQuickItem *eventManagerToFilter() const;
0148     void setEventManagerToFilter(QQuickItem *item);
0149 
0150     EditModeCondition editModeCondition() const;
0151     void setEditModeCondition(EditModeCondition condition);
0152 
0153     bool editMode() const;
0154     void setEditMode(bool edit);
0155 
0156     Q_INVOKABLE void save();
0157     Q_INVOKABLE void showPlaceHolderAt(const QRectF &geom);
0158     Q_INVOKABLE void showPlaceHolderForItem(ItemContainer *item);
0159     Q_INVOKABLE void hidePlaceHolder();
0160 
0161     Q_INVOKABLE bool isRectAvailable(qreal x, qreal y, qreal width, qreal height);
0162     Q_INVOKABLE bool itemIsManaged(ItemContainer *item);
0163     Q_INVOKABLE void positionItem(ItemContainer *item);
0164     Q_INVOKABLE void restoreItem(ItemContainer *item);
0165     Q_INVOKABLE void releaseSpace(ItemContainer *item);
0166 
0167 Q_SIGNALS:
0168     /**
0169      * An applet has been refused by the layout: acceptsAppletCallback
0170      * returned false and will need to be managed in a different way
0171      */
0172     void appletRefused(QObject *applet, int x, int y);
0173 
0174     void configKeyChanged();
0175     void fallbackConfigKeyChanged();
0176     void relayoutLockChanged();
0177     void containmentChanged();
0178     void minimumItemWidthChanged();
0179     void minimumItemHeightChanged();
0180     void defaultItemWidthChanged();
0181     void defaultItemHeightChanged();
0182     void cellWidthChanged();
0183     void cellHeightChanged();
0184     void acceptsAppletCallbackChanged();
0185     void appletContainerComponentChanged();
0186     void placeHolderChanged();
0187     void eventManagerToFilterChanged();
0188     void editModeConditionChanged();
0189     void editModeChanged();
0190     void containmentItemChanged();
0191 
0192 protected:
0193     bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
0194     void updatePolish() override;
0195     void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0196 
0197     // void classBegin() override;
0198     void componentComplete() override;
0199     void mousePressEvent(QMouseEvent *event) override;
0200     void mouseReleaseEvent(QMouseEvent *event) override;
0201 
0202     void touchEvent(QTouchEvent *event) override;
0203     void touchUngrabEvent() override;
0204 
0205 private Q_SLOTS:
0206     void appletAdded(Plasma::Applet *applet);
0207     void appletRemoved(Plasma::Applet *applet);
0208 
0209 private:
0210     AppletContainer *createContainerForApplet(PlasmaQuick::AppletQuickItem *appletItem);
0211 
0212     void handleMoveEvent(const QPointF &scenePosition);
0213     void handleReleaseEvent(const QPointF &scenePosition);
0214 
0215     QString m_configKey;
0216     QString m_fallbackConfigKey;
0217     QTimer *m_saveLayoutTimer;
0218     QTimer *m_layoutChangeTimer;
0219     LayoutChanges m_layoutChanges = NoChange;
0220 
0221     Plasma::Containment *m_containment = nullptr;
0222     QQmlComponent *m_appletContainerComponent = nullptr;
0223     QPointer<PlasmaQuick::AppletQuickItem> m_containmentItem;
0224 
0225     AbstractLayoutManager *m_layoutManager = nullptr;
0226 
0227     QPointer<ItemContainer> m_placeHolder;
0228     QPointer<QQuickItem> m_eventManagerToFilter;
0229 
0230     QTimer *m_pressAndHoldTimer;
0231 
0232     QJSValue m_acceptsAppletCallback;
0233 
0234     AppletsLayout::EditModeCondition m_editModeCondition = AppletsLayout::Manual;
0235 
0236     QHash<PlasmaQuick::AppletQuickItem *, AppletContainer *> m_containerForApplet;
0237 
0238     QSizeF m_minimumItemSize;
0239     QSizeF m_defaultItemSize;
0240     QSizeF m_savedSize;
0241     QRectF m_geometryBeforeResolutionChange;
0242 
0243     QPointF m_touchDownPosition = QPoint(-1, -1);
0244     bool m_touchDownWasEditMode = false;
0245     bool m_editMode = false;
0246     bool m_relayoutLock = false;
0247 };
0248 
0249 Q_DECLARE_OPERATORS_FOR_FLAGS(AppletsLayout::LayoutChanges)