1/*
2 * SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#ifndef OVERLAYZSTACKINGATTACHED_H
8#define OVERLAYZSTACKINGATTACHED_H
9
10#include <QObject>
11#include <QQmlEngine>
12
13#include <qqmlregistration.h>
14
15class QQuickItem;
16
17/*!
18 * \qmltype OverlayZStacking
19 * \inqmlmodule org.kde.kirigami
20 *
21 * \brief An attached property that manages z-index for stacking overlays relative to each other.
22 *
23 * When a popup is about to show, OverlayZStacking object kicks in, searches for the
24 * next nearest popup in the QtQuick hierarchy of items, and sets its z value to the
25 * biggest of two: current stacking value for its layer, or parent's z index + 1.
26 *
27 * This way OverlayZStacking algorithm ensures that a popup is always stacked higher
28 * than its logical parent popup, but also no lower than its siblings on the same
29 * logical layer.
30 *
31 * \code
32 * import QtQuick.Controls as QQC2
33 * import org.kde.kirigami as Kirigami
34 *
35 * QQC2.Popup {
36 * Kirigami.OverlayZStacking.layer: Kirigami.OverlayZStacking.ToolTip
37 * z: Kirigami.OverlayZStacking.z
38 * }
39 * \endcode
40 *
41 * \since 6.0
42 */
43class OverlayZStackingAttached : public QObject
44{
45 Q_OBJECT
46 QML_ELEMENT
47 QML_NAMED_ELEMENT(OverlayZStacking)
48 QML_UNCREATABLE("Cannot create objects of type OverlayZStacking, use it as an attached property")
49 QML_ATTACHED(OverlayZStackingAttached)
50 /*!
51 * \qmlattachedproperty real OverlayZStacking::z
52 *
53 * An optimal z-index that attachee popup should bind to.
54 */
55 Q_PROPERTY(qreal z READ z NOTIFY zChanged FINAL)
56
57 /*!
58 * \qmlattachedproperty enumeration OverlayZStacking::layer
59 *
60 * \qmlenumeratorsfrom OverlayZStackingAttached::Layer
61 *
62 * The logical stacking layer of attachee popup, akin to window manager's layers.
63 */
64 Q_PROPERTY(Layer layer READ layer WRITE setLayer NOTIFY layerChanged FINAL)
65
66public:
67 /*!
68 * \value DefaultLowest
69 * \value Drawer
70 * \value FullScreen
71 * \value Dialog
72 * \value Menu
73 * \value Notification
74 * \value ToolTip
75 */
76 enum Layer {
77 DefaultLowest = 0,
78 Drawer,
79 FullScreen,
80 Dialog,
81 Menu,
82 Notification,
83 ToolTip,
84 };
85 Q_ENUM(Layer)
86
87 explicit OverlayZStackingAttached(QObject *parent = nullptr);
88 ~OverlayZStackingAttached() override;
89
90 qreal z() const;
91
92 Layer layer() const;
93 void setLayer(Layer layer);
94
95 // QML attached property
96 static OverlayZStackingAttached *qmlAttachedProperties(QObject *object);
97
98Q_SIGNALS:
99 void zChanged();
100 void layerChanged();
101
102private Q_SLOTS:
103 // Popup shall not change z index while being open, so if changes arrive, we defer it until closed.
104 void enqueueSignal();
105 void dispatchPendingSignal();
106
107 void updateParentPopup();
108
109private:
110 void updateParentPopupSilent();
111 void setParentPopup(QObject *popup);
112 qreal parentPopupZ() const;
113 static bool isVisible(const QObject *popup);
114 static bool isPopup(const QObject *object);
115 static QObject *findParentPopup(const QObject *popup);
116 static QQuickItem *findParentPopupItem(const QObject *popup);
117 static Layer defaultLayerForPopupType(const QObject *popup);
118 static qreal defaultZForLayer(Layer layer);
119
120 Layer m_layer = Layer::DefaultLowest;
121 QPointer<QObject> m_parentPopup;
122 bool m_pending;
123};
124
125QML_DECLARE_TYPEINFO(OverlayZStackingAttached, QML_HAS_ATTACHED_PROPERTIES)
126
127#endif // OVERLAYZSTACKINGATTACHED_H
128

source code of kirigami/src/overlayzstackingattached.h