diff options
Diffstat (limited to 'src/quicktemplates2/qquickoverlay.cpp')
-rw-r--r-- | src/quicktemplates2/qquickoverlay.cpp | 302 |
1 files changed, 184 insertions, 118 deletions
diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index a1d82de0..38f7949e 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -47,102 +47,42 @@ QT_BEGIN_NAMESPACE -void QQuickOverlayPrivate::popupAboutToShow() -{ - Q_Q(QQuickOverlay); - QQuickPopup *popup = qobject_cast<QQuickPopup *>(q->sender()); - if (!popup || !popup->dim()) - return; - - // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors - QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); - if (p->dimmer) - QQmlProperty::write(p->dimmer, QStringLiteral("opacity"), 1.0); -} - -void QQuickOverlayPrivate::popupAboutToHide() -{ - Q_Q(QQuickOverlay); - QQuickPopup *popup = qobject_cast<QQuickPopup *>(q->sender()); - if (!popup || !popup->dim()) - return; - - // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors - QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); - if (p->dimmer) - QQmlProperty::write(p->dimmer, QStringLiteral("opacity"), 0.0); -} - -static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent) -{ - QQuickItem *item = nullptr; - if (component) { - QQmlContext *creationContext = component->creationContext(); - if (!creationContext) - creationContext = qmlContext(parent); - QQmlContext *context = new QQmlContext(creationContext, parent); - context->setContextObject(popup); - item = qobject_cast<QQuickItem*>(component->beginCreate(context)); - } - - // when there is no overlay component available (with plain QQuickWindow), - // use a plain QQuickItem as a fallback to block hover events - if (!item && popup->isModal()) - item = new QQuickItem; - - if (item) { - item->setOpacity(popup->isVisible() ? 1.0 : 0.0); - item->setParentItem(parent); - item->stackBefore(popup->popupItem()); - item->setZ(popup->z()); - if (popup->isModal()) { - item->setAcceptedMouseButtons(Qt::AllButtons); -#if QT_CONFIG(cursor) - item->setCursor(Qt::ArrowCursor); -#endif -#if QT_CONFIG(quicktemplates2_hover) - // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 - item->setAcceptHoverEvents(true); - // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); - // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents); -#endif +/*! + \qmltype Overlay + \inherits Item + \instantiates QQuickOverlay + \inqmlmodule QtQuick.Controls + \since 5.10 + \brief A window overlay for popups. + + Overlay provides a layer for popups, ensuring that popups are displayed above + other content and that the background is dimmed when a \l {Popup::}{modal} or + \l {Popup::dim}{dimmed} popup is visible. + + The overlay is an ordinary Item that covers the entire window. It can be used + as a visual parent to position a popup in scene coordinates. The following + example uses the attached \c overlay property to position a popup to the center + of the window, despite the position of the button that opens the popup. + + \code + Button { + onClicked: popup.open() + + Popup { + id: popup + + parent: Overlay.overlay + + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: 100 + height: 100 } - if (component) - component->completeCreate(); } - return item; -} + \endcode -void QQuickOverlayPrivate::createOverlay(QQuickPopup *popup) -{ - Q_Q(QQuickOverlay); - QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); - if (!p->dimmer) - p->dimmer = createDimmer(popup->isModal() ? modal : modeless, popup, q); - p->resizeOverlay(); -} - -void QQuickOverlayPrivate::destroyOverlay(QQuickPopup *popup) -{ - QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); - if (p->dimmer) { - p->dimmer->setParentItem(nullptr); - p->dimmer->deleteLater(); - p->dimmer = nullptr; - } -} - -void QQuickOverlayPrivate::toggleOverlay() -{ - Q_Q(QQuickOverlay); - QQuickPopup *popup = qobject_cast<QQuickPopup *>(q->sender()); - if (!popup) - return; - - destroyOverlay(popup); - if (popup->dim()) - createOverlay(popup); -} + \sa ApplicationWindow +*/ QVector<QQuickPopup *> QQuickOverlayPrivate::stackingOrderPopups() const { @@ -461,37 +401,18 @@ QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window) return overlay; } +QQuickOverlayAttached *QQuickOverlay::qmlAttachedProperties(QObject *object) +{ + return new QQuickOverlayAttached(object); +} + void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) { Q_D(QQuickOverlay); QQuickItem::itemChange(change, data); - QQuickPopup *popup = nullptr; - if (change == ItemChildAddedChange || change == ItemChildRemovedChange) { - popup = qobject_cast<QQuickPopup *>(data.item->parent()); + if (change == ItemChildAddedChange || change == ItemChildRemovedChange) setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty()); - } - if (!popup) - return; - - if (change == ItemChildAddedChange) { - if (popup->dim()) - d->createOverlay(popup); - QObjectPrivate::connect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); - QObjectPrivate::connect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); - if (!qobject_cast<QQuickDrawer *>(popup)) { - QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); - QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); - } - } else if (change == ItemChildRemovedChange) { - d->destroyOverlay(popup); - QObjectPrivate::disconnect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); - QObjectPrivate::disconnect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); - if (!qobject_cast<QQuickDrawer *>(popup)) { - QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); - QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); - } - } } void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) @@ -654,4 +575,149 @@ bool QQuickOverlay::eventFilter(QObject *object, QEvent *event) return false; } +class QQuickOverlayAttachedPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickOverlayAttached) + +public: + QQuickOverlayAttachedPrivate() + : window(nullptr), + modal(nullptr), + modeless(nullptr) + { + } + + void setWindow(QQuickWindow *newWindow); + + QQuickWindow *window; + QQmlComponent *modal; + QQmlComponent *modeless; +}; + +void QQuickOverlayAttachedPrivate::setWindow(QQuickWindow *newWindow) +{ + Q_Q(QQuickOverlayAttached); + if (window == newWindow) + return; + + if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window)) { + QObject::disconnect(oldOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed); + QObject::disconnect(oldOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released); + } + + if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(newWindow)) { + QObject::connect(newOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed); + QObject::connect(newOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released); + } + + window = newWindow; + emit q->overlayChanged(); +} + +/*! + \qmlattachedsignal QtQuick.Controls::Overlay::pressed() + + This attached signal is emitted when the overlay is pressed by the user while + a popup is visible. + + The signal can be attached to any item, popup, or window. When attached to an + item or a popup, the signal is only emitted if the item or popup is in a window. +*/ + +/*! + \qmlattachedsignal QtQuick.Controls::Overlay::released() + + This attached signal is emitted when the overlay is released by the user while + a popup is visible. + + The signal can be attached to any item, popup, or window. When attached to an + item or a popup, the signal is only emitted if the item or popup is in a window. +*/ + +QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent) + : QObject(*(new QQuickOverlayAttachedPrivate), parent) +{ + Q_D(QQuickOverlayAttached); + if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) { + d->setWindow(item->window()); + QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow); + } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) { + d->setWindow(popup->window()); + QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow); + } else { + d->setWindow(qobject_cast<QQuickWindow *>(parent)); + } +} + +/*! + \qmlattachedproperty Overlay QtQuick.Controls::Overlay::overlay + \readonly + + This attached property holds the window overlay item. + + The property can be attached to any item, popup, or window. When attached to an + item or a popup, the value is \c null if the item or popup is not in a window. +*/ +QQuickOverlay *QQuickOverlayAttached::overlay() const +{ + Q_D(const QQuickOverlayAttached); + return QQuickOverlay::overlay(d->window); +} + +/*! + \qmlattachedproperty Component QtQuick.Controls::Overlay::modal + + This attached property holds a component to use as a visual item that implements + background dimming for modal popups. It is created for and stacked below visible + modal popups. + + The property can be attached to any popup. + + \sa Popup::modal +*/ +QQmlComponent *QQuickOverlayAttached::modal() const +{ + Q_D(const QQuickOverlayAttached); + return d->modal; +} + +void QQuickOverlayAttached::setModal(QQmlComponent *modal) +{ + Q_D(QQuickOverlayAttached); + if (d->modal == modal) + return; + + delete d->modal; + d->modal = modal; + emit modalChanged(); +} + +/*! + \qmlattachedproperty Component QtQuick.Controls::Overlay::modeless + + This attached property holds a component to use as a visual item that implements + background dimming for modeless popups. It is created for and stacked below visible + dimming popups. + + The property can be attached to any popup. + + \sa Popup::dim +*/ +QQmlComponent *QQuickOverlayAttached::modeless() const +{ + Q_D(const QQuickOverlayAttached); + return d->modeless; +} + +void QQuickOverlayAttached::setModeless(QQmlComponent *modeless) +{ + Q_D(QQuickOverlayAttached); + if (d->modeless == modeless) + return; + + delete d->modeless; + d->modeless = modeless; + emit modelessChanged(); +} + QT_END_NAMESPACE |