File indexing completed on 2024-04-21 03:56:01

0001 /*
0002  *  SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #ifndef OVERLAYZSTACKINGATTACHED_H
0008 #define OVERLAYZSTACKINGATTACHED_H
0009 
0010 #include <QObject>
0011 #include <QQmlEngine>
0012 
0013 #include <qqmlregistration.h>
0014 
0015 class QQuickItem;
0016 
0017 /**
0018  * This attached property manages z-index for stacking overlays relative to each other.
0019  *
0020  * When a popup is about to show, OverlayZStacking object kicks in, searches for the
0021  * next nearest popup in the QtQuick hierarchy of items, and sets its z value to the
0022  * biggest of two: current stacking value for its layer, or parent's z index + 1.
0023  * This way OverlayZStacking algorithm ensures that a popup is always stacked higher
0024  * than its logical parent popup, but also no lower than its siblings on the same
0025  * logical layer.
0026  *
0027  * @code
0028  * import QtQuick.Controls as QQC2
0029  * import org.kde.kirigami as Kirigami
0030  *
0031  * QQC2.Popup {
0032  *     Kirigami.OverlayZStacking.layer: Kirigami.OverlayZStacking.ToolTip
0033  *     z: Kirigami.OverlayZStacking.z
0034  * }
0035  * @endcode
0036  *
0037  * @since 6.0
0038  */
0039 class OverlayZStackingAttached : public QObject
0040 {
0041     Q_OBJECT
0042     QML_ELEMENT
0043     QML_NAMED_ELEMENT(OverlayZStacking)
0044     QML_UNCREATABLE("Cannot create objects of type OverlayZStacking, use it as an attached property")
0045     QML_ATTACHED(OverlayZStackingAttached)
0046     /**
0047      * An optimal z-index that attachee popup should bind to.
0048      */
0049     Q_PROPERTY(qreal z READ z NOTIFY zChanged FINAL)
0050 
0051     /**
0052      * The logical stacking layer of attachee popup, akin to window manager's layers.
0053      */
0054     Q_PROPERTY(Layer layer READ layer WRITE setLayer NOTIFY layerChanged FINAL)
0055 
0056 public:
0057     enum Layer {
0058         DefaultLowest = 0,
0059         Drawer,
0060         FullScreen,
0061         Dialog,
0062         Menu,
0063         Notification,
0064         ToolTip,
0065     };
0066     Q_ENUM(Layer)
0067 
0068     explicit OverlayZStackingAttached(QObject *parent = nullptr);
0069     ~OverlayZStackingAttached() override;
0070 
0071     qreal z() const;
0072 
0073     Layer layer() const;
0074     void setLayer(Layer layer);
0075 
0076     // QML attached property
0077     static OverlayZStackingAttached *qmlAttachedProperties(QObject *object);
0078 
0079 Q_SIGNALS:
0080     void zChanged();
0081     void layerChanged();
0082 
0083 private Q_SLOTS:
0084     // Popup shall not change z index while being open, so if changes arrive, we defer it until closed.
0085     void enqueueSignal();
0086     void dispatchPendingSignal();
0087 
0088     void updateParentPopup();
0089 
0090 private:
0091     void updateParentPopupSilent();
0092     void setParentPopup(QObject *popup);
0093     qreal parentPopupZ() const;
0094     static bool isVisible(const QObject *popup);
0095     static bool isPopup(const QObject *object);
0096     static QObject *findParentPopup(const QObject *popup);
0097     static QQuickItem *findParentPopupItem(const QObject *popup);
0098     static Layer defaultLayerForPopupType(const QObject *popup);
0099     static qreal defaultZForLayer(Layer layer);
0100 
0101     Layer m_layer = Layer::DefaultLowest;
0102     QPointer<QObject> m_parentPopup;
0103     bool m_pending;
0104 };
0105 
0106 QML_DECLARE_TYPEINFO(OverlayZStackingAttached, QML_HAS_ATTACHED_PROPERTIES)
0107 
0108 #endif // OVERLAYZSTACKINGATTACHED_H