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);
214bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target)
217 const bool wasOpened = target->isOpened();
218 if (target->overlayEvent(source, event)) {
219 if (closedItselfViaCloseMultiple(target, wasOpened))
221 setMouseGrabberPopup(target);
227 switch (event->type()) {
229 if (mouseGrabberPopup)
231#if QT_CONFIG(quicktemplates2_multitouch)
233 case QEvent::TouchBegin:
234 case QEvent::TouchUpdate:
235 case QEvent::TouchEnd:
239 if (closeCascadeStopped)
241 const auto popups = stackingOrderPopups();
242 bool passedWithCloseMultiple =
false;
243 for (QQuickPopup *popup : popups) {
244 if (popup->overlayEvent(source, event)) {
249 if (!passedWithCloseMultiple)
250 setMouseGrabberPopup(popup);
253 if (!canCascadeCloseOnOutsidePress(popup))
255 if (!popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
256 closeCascadeStopped =
true;
259 passedWithCloseMultiple =
true;
276bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target)
279 const bool wasOpened = target->isOpened();
280 setMouseGrabberPopup(
nullptr);
281 if (target->overlayEvent(source, event)) {
282 setMouseGrabberPopup(
nullptr);
283 if (!closedItselfViaCloseMultiple(target, wasOpened))
286 }
else if (!closeCascadeStopped) {
287 const auto popups = stackingOrderPopups();
288 for (QQuickPopup *popup : popups) {
289 if (popup->overlayEvent(source, event))
291 if (!canCascadeCloseOnOutsidePress(popup))
293 if (!popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
294 closeCascadeStopped =
true;
302bool QQuickOverlayPrivate::handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target)
304 switch (event->type()) {
305 case QEvent::MouseButtonPress:
306 if (!target && startDrag(event, event->scenePosition()))
308 return handlePress(source, event, target);
309 case QEvent::MouseMove:
310 return handleMove(source, event, target ? target : mouseGrabberPopup.data());
311 case QEvent::MouseButtonRelease:
312 return handleRelease(source, event, target ? target : mouseGrabberPopup.data());
410QQuickOverlay::QQuickOverlay(QQuickItem *parent)
411 : QQuickItem(*(
new QQuickOverlayPrivate), parent)
415 setAcceptedMouseButtons(Qt::AllButtons);
416#if QT_CONFIG(quicktemplates2_multitouch)
417 setAcceptTouchEvents(
true);
419 setFiltersChildMouseEvents(
true);
424 QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry);
425 if (QQuickWindow *window = parent->window()) {
426 window->installEventFilter(
this);
427 if (QQuickItem *contentItem = window->contentItem())
428 QQuickItemPrivate::get(contentItem)->addItemChangeListener(d, QQuickItemPrivate::Rotation);
477QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window, QQuickItem *parent)
482 const char *name =
"_q_QQuickOverlay";
484 if (QQuickItemPrivate::customOverlayRequested) {
486 if (QQuickItemPrivate::get(parent)->customOverlay) {
487 QQuickOverlay *overlay = parent->property(name).value<QQuickOverlay *>();
489 overlay =
new QQuickOverlay(parent);
490 parent->setProperty(name, QVariant::fromValue(overlay));
494 parent = parent->parentItem();
497 QQuickOverlay *overlay = window->property(name).value<QQuickOverlay *>();
499 QQuickItem *content = window->contentItem();
502 if (content && content->window()) {
503 overlay =
new QQuickOverlay(window->contentItem());
504 window->setProperty(name, QVariant::fromValue(overlay));
618bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
628 const bool isCloseCascadeEvent = event->type() == QEvent::MouseButtonPress
629 || event->type() == QEvent::MouseButtonRelease
630#if QT_CONFIG(quicktemplates2_multitouch)
631 || event->type() == QEvent::TouchBegin
632 || event->type() == QEvent::TouchUpdate
633 || event->type() == QEvent::TouchEnd
636 if (isCloseCascadeEvent && d->closeCascadeStopped)
639 const auto popups = d->stackingOrderPopups();
640 for (qsizetype i = 0; i < popups.size(); ++i) {
641 QQuickPopup *popup = popups.at(i);
642 QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
646 if (item == p->popupItem || p->popupItem->isAncestorOf(item))
652 if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) {
653 bool handled =
false;
654 switch (event->type()) {
655#if QT_CONFIG(quicktemplates2_multitouch)
656 case QEvent::TouchBegin:
657 case QEvent::TouchUpdate:
658 case QEvent::TouchEnd:
659 handled = d->handleTouchEvent(item,
static_cast<QTouchEvent *>(event), popup);
662 case QEvent::HoverEnter:
663 case QEvent::HoverMove:
664 case QEvent::HoverLeave:
668 if (
auto *control = qobject_cast<QQuickControl *>(item)) {
669 if (control->isHovered() && event->type() == QEvent::HoverLeave)
672 handled = d->handleHoverEvent(item,
static_cast<QHoverEvent *>(event), popup);
675 case QEvent::MouseButtonPress:
676 case QEvent::MouseButtonRelease:
677 case QEvent::MouseMove:
678 handled = d->handleMouseEvent(item,
static_cast<QMouseEvent *>(event), popup);
695 if (event->type() == QEvent::MouseButtonPress && isCloseCascadeEvent
696 && canCascadeCloseOnOutsidePress(popup)
697 && popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
698 auto *mouseEvent =
static_cast<QMouseEvent *>(event);
699 for (qsizetype j = i + 1; j < popups.size(); ++j) {
700 QQuickPopup *lower = popups.at(j);
701 QQuickPopupPrivate::get(lower)->handlePress(
702 item, mouseEvent->scenePosition(), mouseEvent->timestamp());
703 if (canCascadeCloseOnOutsidePress(lower)
704 && !lower->closePolicy().testFlag(QQuickPopup::CloseMultiple))
716 if (isCloseCascadeEvent && canCascadeCloseOnOutsidePress(popup)
717 && !popup->closePolicy().testFlag(QQuickPopup::CloseMultiple)) {
718 d->closeCascadeStopped =
true;
742bool QQuickOverlay::eventFilter(QObject *object, QEvent *event)
745 if (!isVisible() || object != d->window)
748#if QT_CONFIG(wheelevent) || QT_CONFIG(quick_draganddrop)
749 auto targetItemsForEvent = [&](QEvent *){
750#if QT_CONFIG(wheelevent)
751 if (event->type() == QEvent::Wheel) {
752 QWheelEvent *we =
static_cast<QWheelEvent *>(event);
753 return d->deliveryAgentPrivate()->pointerTargets(
754 d->window->contentItem(), we, we->point(0),
false,
false);
757#if QT_CONFIG(quick_draganddrop)
758 bool isDnDEvent =
false;
759 switch (event->type()) {
760 case QEvent::DragEnter:
761 case QEvent::DragMove:
769 QDropEvent *de =
static_cast<QDropEvent *>(event);
770 auto position = mapFromScene(de->position());
771 return d->deliveryAgentPrivate()->eventTargets(
772 d->window->contentItem(), de, -1, position, de->position(),
773 [](QQuickItem *item,
const QEvent *) -> std::optional<
bool> {
776 if (!item->flags().testFlag(QQuickItem::ItemAcceptsDrops))
783 Q_UNREACHABLE_RETURN(QList<QQuickItem *> {});
787 switch (event->type()) {
788#if QT_CONFIG(quicktemplates2_multitouch)
789 case QEvent::TouchBegin:
790 case QEvent::TouchUpdate:
791 case QEvent::TouchEnd:
792 if (
static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Pressed)
794 if (
static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Released)
798 d->closeCascadeStopped =
false;
801 if (!d->mouseGrabberPopup) {
802 QTouchEvent *touchEvent =
static_cast<QTouchEvent *>(event);
803 for (
const QTouchEvent::TouchPoint &point : touchEvent->points()) {
804 if (point.state() == QEventPoint::Released) {
805 QQuickDeliveryAgentPrivate::translateTouchEvent(touchEvent);
806 if (d->handleRelease(d->window->contentItem(), event,
nullptr))
813 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
814 d->deliveryAgentPrivate()->handleTouchEvent(
static_cast<QTouchEvent *>(event));
815 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent =
nullptr;
824 d->deliveryAgentPrivate()->clearGrabbers(
static_cast<QPointerEvent *>(event));
828 case QEvent::MouseButtonPress: {
829 auto *mouseEvent =
static_cast<QMouseEvent *>(event);
834 if (mouseEvent->button() == Qt::RightButton)
837#if QT_CONFIG(quicktemplates2_multitouch)
839 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
844 d->closeCascadeStopped =
false;
847 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
848 d->deliveryAgentPrivate()->handleMouseEvent(mouseEvent);
849 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent =
nullptr;
858 case QEvent::MouseButtonRelease: {
859 auto *mouseEvent =
static_cast<QMouseEvent *>(event);
860 if (mouseEvent->button() == Qt::RightButton)
863#if QT_CONFIG(quicktemplates2_multitouch)
865 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
870 d->closeCascadeStopped =
false;
873 if (!d->mouseGrabberPopup)
874 d->handleRelease(d->window->contentItem(), event,
nullptr);
877#if QT_CONFIG(quick_draganddrop)
878 case QEvent::DragEnter:
879 case QEvent::DragMove:
882 const QList<QQuickItem *> targetItems = targetItemsForEvent(event);
883 if (targetItems.isEmpty())
885 QQuickItem *
const dimmerItem = property(
"_q_dimmerItem").value<QQuickItem *>();
886 QQuickItem *
const topItem = targetItems.first();
887 QQuickItem *item = qobject_cast<QQuickPopupItem *>(topItem) ? topItem :
nullptr;
890 while ((item = item->parentItem())) {
891 if (qobject_cast<QQuickPopupItem *>(item))
895 if (!item && dimmerItem != topItem && isAncestorOf(topItem))
897 for (
const auto &popup : d->stackingOrderPopups()) {
898 const QQuickItem *popupItem = popup->popupItem();
901 if (popupItem == item)
903 if (popup->overlayEvent(topItem, event))
909#if QT_CONFIG(wheelevent)
911 return d->eatEventIfBlockedByModal(
static_cast<QWheelEvent *>(event));
913#if QT_CONFIG(tabletevent)
914 case QEvent::TabletMove:
915 case QEvent::TabletPress:
916 case QEvent::TabletRelease:
917 return d->eatEventIfBlockedByModal(
static_cast<QTabletEvent *>(event));
947 Q_Q(QQuickOverlayAttached);
948 if (window == newWindow)
951 if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window, parent)) {
952 QObject::disconnect(oldOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
953 QObject::disconnect(oldOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
956 if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(newWindow, parent)) {
957 QObject::connect(newOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
958 QObject::connect(newOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
964 emit q->overlayChanged();
991QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent)
992 : QObject(*(
new QQuickOverlayAttachedPrivate), parent)
994 Q_D(QQuickOverlayAttached);
995 if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
996 d->setWindowAndParent(item->window(), item);
997 QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
998 }
else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
999 d->setWindowAndParent(popup->window(), popup->parentItem());
1000 QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
1002 d->setWindow(qobject_cast<QQuickWindow *>(parent));