153bool QQuickOverlayPrivate::startDrag(QEvent *event,
const QPointF &pos)
156 if (allDrawers.isEmpty())
160 QQuickItem *item = q->childAt(pos.x(), pos.y());
162 const auto popups = stackingOrderPopups();
163 for (QQuickPopup *popup : popups) {
164 QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
165 if (p->dimmer == item && popup->isVisible() && popup->isModal())
170 const QList<QQuickPopup *> drawers = stackingOrderDrawers();
171 for (QQuickPopup *popup : drawers) {
172 QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup);
174 QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer);
175 if (p->startDrag(event)) {
176 setMouseGrabberPopup(drawer);
219bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target)
222 const bool wasOpened = target->isOpened();
223 if (target->overlayEvent(source, event)) {
224 if (closedItselfViaCloseMultiple(target, wasOpened))
226 setMouseGrabberPopup(target);
232 switch (event->type()) {
234 if (mouseGrabberPopup)
236#if QT_CONFIG(quicktemplates2_multitouch)
238 case QEvent::TouchBegin:
239 case QEvent::TouchUpdate:
240 case QEvent::TouchEnd:
244 const auto popups = stackingOrderPopups();
245 bool passedWithCloseMultiple =
false;
246 for (QQuickPopup *popup : popups) {
247 if (closeCascadeStopped) {
248 if (blocksWithoutClosing(popup, source, event))
252 if (popup->overlayEvent(source, event)) {
257 if (!passedWithCloseMultiple)
258 setMouseGrabberPopup(popup);
261 if (!canCascadeCloseOnOutsidePress(popup))
263 if (!popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
264 closeCascadeStopped =
true;
267 passedWithCloseMultiple =
true;
284bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target)
287 const bool wasOpened = target->isOpened();
288 setMouseGrabberPopup(
nullptr);
289 if (target->overlayEvent(source, event)) {
290 setMouseGrabberPopup(
nullptr);
291 if (!closedItselfViaCloseMultiple(target, wasOpened))
294 }
else if (!closeCascadeStopped) {
295 const auto popups = stackingOrderPopups();
296 for (QQuickPopup *popup : popups) {
297 if (popup->overlayEvent(source, event))
299 if (!canCascadeCloseOnOutsidePress(popup))
301 if (!popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
302 closeCascadeStopped =
true;
310bool QQuickOverlayPrivate::handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target)
312 switch (event->type()) {
313 case QEvent::MouseButtonPress:
314 if (!target && startDrag(event, event->scenePosition()))
316 return handlePress(source, event, target);
317 case QEvent::MouseMove:
318 return handleMove(source, event, target ? target : mouseGrabberPopup.data());
319 case QEvent::MouseButtonRelease:
320 return handleRelease(source, event, target ? target : mouseGrabberPopup.data());
418QQuickOverlay::QQuickOverlay(QQuickItem *parent)
419 : QQuickItem(*(
new QQuickOverlayPrivate), parent)
423 setAcceptedMouseButtons(Qt::AllButtons);
424#if QT_CONFIG(quicktemplates2_multitouch)
425 setAcceptTouchEvents(
true);
427 setFiltersChildMouseEvents(
true);
432 QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry);
433 if (QQuickWindow *window = parent->window()) {
434 window->installEventFilter(
this);
435 if (QQuickItem *contentItem = window->contentItem())
436 QQuickItemPrivate::get(contentItem)->addItemChangeListener(d, QQuickItemPrivate::Rotation);
485QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window, QQuickItem *parent)
490 const char *name =
"_q_QQuickOverlay";
492 if (QQuickItemPrivate::customOverlayRequested) {
494 if (QQuickItemPrivate::get(parent)->customOverlay) {
495 QQuickOverlay *overlay = parent->property(name).value<QQuickOverlay *>();
497 overlay =
new QQuickOverlay(parent);
498 parent->setProperty(name, QVariant::fromValue(overlay));
502 parent = parent->parentItem();
505 QQuickOverlay *overlay = window->property(name).value<QQuickOverlay *>();
507 QQuickItem *content = window->contentItem();
510 if (content && content->window()) {
511 overlay =
new QQuickOverlay(window->contentItem());
512 window->setProperty(name, QVariant::fromValue(overlay));
626bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
636 const bool isCloseCascadeEvent = event->type() == QEvent::MouseButtonPress
637 || event->type() == QEvent::MouseButtonRelease
638#if QT_CONFIG(quicktemplates2_multitouch)
639 || event->type() == QEvent::TouchBegin
640 || event->type() == QEvent::TouchUpdate
641 || event->type() == QEvent::TouchEnd
644 const auto popups = d->stackingOrderPopups();
645 for (qsizetype i = 0; i < popups.size(); ++i) {
646 QQuickPopup *popup = popups.at(i);
647 QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
651 if (item == p->popupItem || p->popupItem->isAncestorOf(item))
654 if (isCloseCascadeEvent && d->closeCascadeStopped) {
655 if (blocksWithoutClosing(popup, item, event))
663 if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) {
664 bool handled =
false;
665 switch (event->type()) {
666#if QT_CONFIG(quicktemplates2_multitouch)
667 case QEvent::TouchBegin:
668 case QEvent::TouchUpdate:
669 case QEvent::TouchEnd:
670 handled = d->handleTouchEvent(item,
static_cast<QTouchEvent *>(event), popup);
673 case QEvent::HoverEnter:
674 case QEvent::HoverMove:
675 case QEvent::HoverLeave:
679 if (
auto *control = qobject_cast<QQuickControl *>(item)) {
680 if (control->isHovered() && event->type() == QEvent::HoverLeave)
683 handled = d->handleHoverEvent(item,
static_cast<QHoverEvent *>(event), popup);
686 case QEvent::MouseButtonPress:
687 case QEvent::MouseButtonRelease:
688 case QEvent::MouseMove:
689 handled = d->handleMouseEvent(item,
static_cast<QMouseEvent *>(event), popup);
706 if (event->type() == QEvent::MouseButtonPress && isCloseCascadeEvent
707 && canCascadeCloseOnOutsidePress(popup)
708 && popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
709 auto *mouseEvent =
static_cast<QMouseEvent *>(event);
710 for (qsizetype j = i + 1; j < popups.size(); ++j) {
711 QQuickPopup *lower = popups.at(j);
712 QQuickPopupPrivate::get(lower)->handlePress(
713 item, mouseEvent->scenePosition(), mouseEvent->timestamp());
714 if (canCascadeCloseOnOutsidePress(lower)
715 && !lower->closePolicy().testFlag(QQuickPopup::CloseMultiple))
727 if (isCloseCascadeEvent && canCascadeCloseOnOutsidePress(popup)
728 && !popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
729 d->closeCascadeStopped =
true;
752bool QQuickOverlay::eventFilter(QObject *object, QEvent *event)
755 if (!isVisible() || object != d->window)
758#if QT_CONFIG(wheelevent) || QT_CONFIG(quick_draganddrop)
759 auto targetItemsForEvent = [&](QEvent *){
760#if QT_CONFIG(wheelevent)
761 if (event->type() == QEvent::Wheel) {
762 QWheelEvent *we =
static_cast<QWheelEvent *>(event);
763 return d->deliveryAgentPrivate()->pointerTargets(
764 d->window->contentItem(), we, we->point(0),
false,
false);
767#if QT_CONFIG(quick_draganddrop)
768 bool isDnDEvent =
false;
769 switch (event->type()) {
770 case QEvent::DragEnter:
771 case QEvent::DragMove:
779 QDropEvent *de =
static_cast<QDropEvent *>(event);
780 auto position = mapFromScene(de->position());
781 return d->deliveryAgentPrivate()->eventTargets(
782 d->window->contentItem(), de, -1, position, de->position(),
783 [](QQuickItem *item,
const QEvent *) -> std::optional<
bool> {
786 if (!item->flags().testFlag(QQuickItem::ItemAcceptsDrops))
793 Q_UNREACHABLE_RETURN(QList<QQuickItem *> {});
797 switch (event->type()) {
798#if QT_CONFIG(quicktemplates2_multitouch)
799 case QEvent::TouchBegin:
800 case QEvent::TouchUpdate:
801 case QEvent::TouchEnd:
802 if (
static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Pressed)
804 if (
static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Released)
808 d->closeCascadeStopped =
false;
811 if (!d->mouseGrabberPopup) {
812 QTouchEvent *touchEvent =
static_cast<QTouchEvent *>(event);
813 for (
const QTouchEvent::TouchPoint &point : touchEvent->points()) {
814 if (point.state() == QEventPoint::Released) {
815 QQuickDeliveryAgentPrivate::translateTouchEvent(touchEvent);
816 if (d->handleRelease(d->window->contentItem(), event,
nullptr))
823 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
824 d->deliveryAgentPrivate()->handleTouchEvent(
static_cast<QTouchEvent *>(event));
825 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent =
nullptr;
834 d->deliveryAgentPrivate()->clearGrabbers(
static_cast<QPointerEvent *>(event));
838 case QEvent::MouseButtonPress: {
839 auto *mouseEvent =
static_cast<QMouseEvent *>(event);
844 if (mouseEvent->button() == Qt::RightButton)
847#if QT_CONFIG(quicktemplates2_multitouch)
849 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
854 d->closeCascadeStopped =
false;
857 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
858 d->deliveryAgentPrivate()->handleMouseEvent(mouseEvent);
859 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent =
nullptr;
868 case QEvent::MouseButtonRelease: {
869 auto *mouseEvent =
static_cast<QMouseEvent *>(event);
870 if (mouseEvent->button() == Qt::RightButton)
873#if QT_CONFIG(quicktemplates2_multitouch)
875 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
880 d->closeCascadeStopped =
false;
883 if (!d->mouseGrabberPopup)
884 d->handleRelease(d->window->contentItem(), event,
nullptr);
887#if QT_CONFIG(quick_draganddrop)
888 case QEvent::DragEnter:
889 case QEvent::DragMove:
892 const QList<QQuickItem *> targetItems = targetItemsForEvent(event);
893 if (targetItems.isEmpty())
895 QQuickItem *
const dimmerItem = property(
"_q_dimmerItem").value<QQuickItem *>();
896 QQuickItem *
const topItem = targetItems.first();
897 QQuickItem *item = qobject_cast<QQuickPopupItem *>(topItem) ? topItem :
nullptr;
900 while ((item = item->parentItem())) {
901 if (qobject_cast<QQuickPopupItem *>(item))
905 if (!item && dimmerItem != topItem && isAncestorOf(topItem))
907 for (
const auto &popup : d->stackingOrderPopups()) {
908 const QQuickItem *popupItem = popup->popupItem();
911 if (popupItem == item)
913 if (popup->overlayEvent(topItem, event))
919#if QT_CONFIG(wheelevent)
921 return d->eatEventIfBlockedByModal(
static_cast<QWheelEvent *>(event));
923#if QT_CONFIG(tabletevent)
924 case QEvent::TabletMove:
925 case QEvent::TabletPress:
926 case QEvent::TabletRelease:
927 return d->eatEventIfBlockedByModal(
static_cast<QTabletEvent *>(event));
957 Q_Q(QQuickOverlayAttached);
958 if (window == newWindow)
961 if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window, parent)) {
962 QObject::disconnect(oldOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
963 QObject::disconnect(oldOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
966 if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(newWindow, parent)) {
967 QObject::connect(newOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
968 QObject::connect(newOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
974 emit q->overlayChanged();
1001QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent)
1002 : QObject(*(
new QQuickOverlayAttachedPrivate), parent)
1004 Q_D(QQuickOverlayAttached);
1005 if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
1006 d->setWindowAndParent(item->window(), item);
1007 QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
1008 }
else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
1009 d->setWindowAndParent(popup->window(), popup->parentItem());
1010 QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
1012 d->setWindow(qobject_cast<QQuickWindow *>(parent));