/* * SPDX-FileCopyrightText: 2023 ivan tkachenko * * SPDX-License-Identifier: LGPL-2.0-or-later */ #include "overlayzstackingattached.h" #include "loggingcategory.h" #include OverlayZStackingAttached::OverlayZStackingAttached(QObject *parent) : QObject(parent) , m_layer(defaultLayerForPopupType(parent)) , m_parentPopup(nullptr) , m_pending(false) { Q_ASSERT(parent); if (!isPopup(parent)) { qCWarning(KirigamiLog) << "OverlayZStacking must be attached to a Popup"; return; } connect(parent, SIGNAL(parentChanged()), this, SLOT(updateParentPopup())); connect(parent, SIGNAL(closed()), this, SLOT(dispatchPendingSignal())); // Note: aboutToShow is too late, as QQuickPopup has already created modal // dimmer based off current z index. } OverlayZStackingAttached::~OverlayZStackingAttached() { } qreal OverlayZStackingAttached::z() const { if (!m_parentPopup) { const_cast(this)->updateParentPopupSilent(); } qreal layerZ = defaultZForLayer(m_layer); qreal parentZ = parentPopupZ() + 1; return std::max(layerZ, parentZ); } OverlayZStackingAttached::Layer OverlayZStackingAttached::layer() const { return m_layer; } void OverlayZStackingAttached::setLayer(Layer layer) { if (m_layer == layer) { return; } m_layer = layer; Q_EMIT layerChanged(); enqueueSignal(); } OverlayZStackingAttached *OverlayZStackingAttached::qmlAttachedProperties(QObject *object) { return new OverlayZStackingAttached(object); } void OverlayZStackingAttached::enqueueSignal() { if (isVisible(parent())) { m_pending = true; } else { Q_EMIT zChanged(); } } void OverlayZStackingAttached::dispatchPendingSignal() { if (m_pending) { m_pending = false; Q_EMIT zChanged(); } } void OverlayZStackingAttached::updateParentPopup() { const qreal oldZ = parentPopupZ(); updateParentPopupSilent(); if (oldZ != parentPopupZ()) { enqueueSignal(); } } void OverlayZStackingAttached::updateParentPopupSilent() { auto popup = findParentPopup(parent()); setParentPopup(popup); } void OverlayZStackingAttached::setParentPopup(QObject *parentPopup) { if (m_parentPopup == parentPopup) { return; } if (m_parentPopup) { disconnect(m_parentPopup.data(), SIGNAL(zChanged()), this, SLOT(enqueueSignal())); } // Ideally, we would also connect to all the parent items' parentChanged() on the way to parent popup. m_parentPopup = parentPopup; if (m_parentPopup) { connect(m_parentPopup.data(), SIGNAL(zChanged()), this, SLOT(enqueueSignal())); } } qreal OverlayZStackingAttached::parentPopupZ() const { if (m_parentPopup) { return m_parentPopup->property("z").toReal(); } return -1; } bool OverlayZStackingAttached::isVisible(const QObject *popup) { if (!isPopup(popup)) { return false; } return popup->property("visible").toBool(); } bool OverlayZStackingAttached::isPopup(const QObject *object) { return object && object->inherits("QQuickPopup"); } QObject *OverlayZStackingAttached::findParentPopup(const QObject *popup) { auto item = findParentPopupItem(popup); if (!item) { return nullptr; } auto parentPopup = item->parent(); if (!isPopup(popup)) { return nullptr; } return parentPopup; } QQuickItem *OverlayZStackingAttached::findParentPopupItem(const QObject *popup) { if (!isPopup(popup)) { return nullptr; } QQuickItem *parentItem = popup->property("parent").value(); if (!parentItem) { return nullptr; } QQuickItem *item = parentItem; do { if (item && item->inherits("QQuickPopupItem")) { return item; } item = item->parentItem(); } while (item); return nullptr; } OverlayZStackingAttached::Layer OverlayZStackingAttached::defaultLayerForPopupType(const QObject *popup) { if (popup) { if (popup->inherits("QQuickDialog")) { return Layer::Dialog; } else if (popup->inherits("QQuickDrawer")) { return Layer::Drawer; } else if (popup->inherits("QQuickMenu")) { return Layer::Menu; } else if (popup->inherits("QQuickToolTip")) { return Layer::ToolTip; } } return DefaultLowest; } qreal OverlayZStackingAttached::defaultZForLayer(Layer layer) { switch (layer) { case DefaultLowest: return 0; case Drawer: return 100; case FullScreen: return 200; case Dialog: return 300; case Menu: return 400; case Notification: return 500; case ToolTip: return 600; } return 0; } #include "moc_overlayzstackingattached.cpp"