/* SPDX-FileCopyrightText: 2019 Marco Martin SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include #include #include #include "appletslayout.h" class QTimer; class ConfigOverlay; class ItemContainer : public QQuickItem { Q_OBJECT QML_ELEMENT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(AppletsLayout *layout READ layout NOTIFY layoutChanged) // TODO: make it unchangeable? probably not Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged) Q_PROPERTY(ItemContainer::EditModeCondition editModeCondition READ editModeCondition WRITE setEditModeCondition NOTIFY editModeConditionChanged) Q_PROPERTY(bool editMode READ editMode WRITE setEditMode NOTIFY editModeChanged) Q_PROPERTY(bool dragActive READ dragActive NOTIFY dragActiveChanged) Q_PROPERTY(AppletsLayout::PreferredLayoutDirection preferredLayoutDirection READ preferredLayoutDirection WRITE setPreferredLayoutDirection NOTIFY preferredLayoutDirectionChanged) Q_PROPERTY(QUrl configOverlaySource READ configOverlaySource WRITE setConfigOverlaySource NOTIFY configOverlaySourceChanged) Q_PROPERTY(bool configOverlayVisible READ configOverlayVisible WRITE setConfigOverlayVisible NOTIFY configOverlayVisibleChanged) Q_PROPERTY(QQuickItem *configOverlayItem READ configOverlayItem NOTIFY configOverlayItemChanged) /** * Initial size this container asks to have upon creation. only positive values are considered */ Q_PROPERTY(QSizeF initialSize READ initialSize WRITE setInitialSize NOTIFY initialSizeChanged) // From there mostly a clone of QQC2 Control Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged) Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged) /** * Padding adds a space between each edge of the content item and the background item, effectively controlling the size of the content item. */ Q_PROPERTY(int leftPadding READ leftPadding WRITE setLeftPadding NOTIFY leftPaddingChanged) Q_PROPERTY(int rightPadding READ rightPadding WRITE setRightPadding NOTIFY rightPaddingChanged) Q_PROPERTY(int topPadding READ topPadding WRITE setTopPadding NOTIFY topPaddingChanged) Q_PROPERTY(int bottomPadding READ bottomPadding WRITE setBottomPadding NOTIFY bottomPaddingChanged) /** * The size of the contents: the size of this item minus the padding */ Q_PROPERTY(int contentWidth READ contentWidth NOTIFY contentWidthChanged) Q_PROPERTY(int contentHeight READ contentHeight NOTIFY contentHeightChanged) Q_PROPERTY(QQmlListProperty contentData READ contentData FINAL) // Q_CLASSINFO("DeferredPropertyNames", "background,contentItem") Q_CLASSINFO("DefaultProperty", "contentData") public: enum EditModeCondition { Locked = AppletsLayout::EditModeCondition::Locked, Manual = AppletsLayout::EditModeCondition::Manual, AfterPressAndHold = AppletsLayout::EditModeCondition::AfterPressAndHold, AfterPress, AfterMouseOver, }; Q_ENUMS(EditModeCondition) ItemContainer(QQuickItem *parent = nullptr); ~ItemContainer(); QQmlListProperty contentData(); QString key() const; void setKey(const QString &id); bool editMode() const; void setEditMode(bool edit); bool dragActive() const; Q_INVOKABLE void cancelEdit(); EditModeCondition editModeCondition() const; void setEditModeCondition(EditModeCondition condition); AppletsLayout::PreferredLayoutDirection preferredLayoutDirection() const; void setPreferredLayoutDirection(AppletsLayout::PreferredLayoutDirection direction); QUrl configOverlaySource() const; void setConfigOverlaySource(const QUrl &url); bool configOverlayVisible() const; void setConfigOverlayVisible(bool visible); // TODO: keep this accessible? ConfigOverlay *configOverlayItem() const; QSizeF initialSize() const; void setInitialSize(const QSizeF &size); // Control-like api QQuickItem *contentItem() const; void setContentItem(QQuickItem *item); QQuickItem *background() const; void setBackground(QQuickItem *item); // Setters and getters for the padding int leftPadding() const; void setLeftPadding(int padding); int topPadding() const; void setTopPadding(int padding); int rightPadding() const; void setRightPadding(int padding); int bottomPadding() const; void setBottomPadding(int padding); int contentWidth() const; int contentHeight() const; AppletsLayout *layout() const; // Not for QML void setLayout(AppletsLayout *layout); QObject *layoutAttached() const { return m_layoutAttached; } protected: void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; // void classBegin() override; void componentComplete() override; bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseUngrabEvent() override; void hoverEnterEvent(QHoverEvent *event) override; void hoverLeaveEvent(QHoverEvent *event) override; Q_SIGNALS: /** * The user manually dragged the ItemContainer around * @param newPosition new position of the ItemContainer in parent coordinates * @param dragCenter position in ItemContainer coordinates of the drag hotspot, i.e. where the user pressed the mouse or the * finger over the ItemContainer */ void userDrag(const QPointF &newPosition, const QPointF &dragCenter); void dragActiveChanged(); /** * The attached layout object changed some of its size hints */ void sizeHintsChanged(); // QML property notifiers void layoutChanged(); void keyChanged(); void editModeConditionChanged(); void editModeChanged(bool editMode); void preferredLayoutDirectionChanged(); void configOverlaySourceChanged(); void configOverlayItemChanged(); void initialSizeChanged(); void configOverlayVisibleChanged(bool configOverlayVisile); void backgroundChanged(); void contentItemChanged(); void leftPaddingChanged(); void rightPaddingChanged(); void topPaddingChanged(); void bottomPaddingChanged(); void contentWidthChanged(); void contentHeightChanged(); private Q_SLOTS: void onConfigOverlayComponentStatusChanged(QQmlComponent::Status status, QQmlComponent *component = nullptr); private: void syncChildItemsGeometry(const QSizeF &size); void sendUngrabRecursive(QQuickItem *item); void loadConfigOverlayItem(); // internal accessorts for the contentData QProperty static void contentData_append(QQmlListProperty *prop, QObject *object); static qsizetype contentData_count(QQmlListProperty *prop); static QObject *contentData_at(QQmlListProperty *prop, qsizetype index); static void contentData_clear(QQmlListProperty *prop); QPointer m_contentItem; QPointer m_backgroundItem; // Internal implementation detail: this is used to reparent all items to contentItem QList m_contentData; /** * Padding adds a space between each edge of the content item and the background item, effectively controlling the size of the content item. */ int m_leftPadding = 0; int m_rightPadding = 0; int m_topPadding = 0; int m_bottomPadding = 0; QString m_key; QPointer m_layout; QTimer *m_editModeTimer = nullptr; QTimer *m_closeEditModeTimer = nullptr; QTimer *m_sizeHintAdjustTimer = nullptr; QObject *m_layoutAttached = nullptr; EditModeCondition m_editModeCondition = Manual; QSizeF m_initialSize; QUrl m_configOverlaySource; ConfigOverlay *m_configOverlay = nullptr; bool m_configOverlayVisible = false; QPointF m_lastMousePosition = QPoint(-1, -1); QPointF m_mouseDownPosition = QPoint(-1, -1); AppletsLayout::PreferredLayoutDirection m_preferredLayoutDirection = AppletsLayout::Closest; bool m_editMode = false; bool m_mouseDown = false; bool m_mouseSynthetizedFromTouch = false; bool m_dragActive = false; };