2022-03-05 22:41:29 +05:00

234 lines
8.2 KiB
C++

/*
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include <QPointer>
#include <QQmlParserStatus>
#include <QQuickItem>
#include "appletslayout.h"
class QTimer;
class ConfigOverlay;
class ItemContainer : public QQuickItem
{
Q_OBJECT
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(QQmlComponent *configOverlayComponent READ configOverlayComponent WRITE setConfigOverlayComponent NOTIFY configOverlayComponentChanged)
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<QObject> 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<QObject> 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);
QQmlComponent *configOverlayComponent() const;
void setConfigOverlayComponent(QQmlComponent *component);
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 geometryChanged(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 configOverlayComponentChanged();
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:
void syncChildItemsGeometry(const QSizeF &size);
void sendUngrabRecursive(QQuickItem *item);
// internal accessorts for the contentData QProperty
static void contentData_append(QQmlListProperty<QObject> *prop, QObject *object);
static int contentData_count(QQmlListProperty<QObject> *prop);
static QObject *contentData_at(QQmlListProperty<QObject> *prop, int index);
static void contentData_clear(QQmlListProperty<QObject> *prop);
QPointer<QQuickItem> m_contentItem;
QPointer<QQuickItem> m_backgroundItem;
// Internal implementation detail: this is used to reparent all items to contentItem
QList<QObject *> 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<AppletsLayout> 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;
QPointer<QQmlComponent> m_configOverlayComponent;
ConfigOverlay *m_configOverlay = nullptr;
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;
};