Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickoverlay.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
10#include "qquickdrawer_p.h"
13#include <QtGui/qpainterpath.h>
14#include <QtQml/qqmlinfo.h>
15#include <QtQml/qqmlproperty.h>
16#include <QtQml/qqmlcomponent.h>
17#include <algorithm>
18
19QT_BEGIN_NAMESPACE
20
21/*!
22 \qmltype Overlay
23 \inherits Item
24//! \nativetype QQuickOverlay
25 \inqmlmodule QtQuick.Controls
26 \since 5.10
27 \brief A window overlay for popups.
28
29 Overlay provides a layer for popups, ensuring that popups are displayed above
30 other content and that the background is dimmed when a \l {Popup::}{modal} or
31 \l {Popup::dim}{dimmed} popup is visible.
32
33 The overlay is an ordinary Item that covers the entire window. It can be used
34 as a visual parent to position a popup in scene coordinates.
35
36 \include qquickoverlay-popup-parent.qdocinc
37
38 \sa ApplicationWindow
39*/
40
41QList<QQuickPopup *> QQuickOverlayPrivate::stackingOrderPopups() const
42{
43 const QList<QQuickItem *> children = paintOrderChildItems();
44
45 QList<QQuickPopup *> popups;
46 popups.reserve(children.size());
47
48 for (auto it = children.crbegin(), end = children.crend(); it != end; ++it) {
49 QQuickPopup *popup = qobject_cast<QQuickPopup *>((*it)->parent());
50 if (popup)
51 popups += popup;
52 }
53
54 return popups;
55}
56
57QList<QQuickPopup *> QQuickOverlayPrivate::stackingOrderDrawers() const
58{
59 QList<QQuickPopup *> sorted(allDrawers);
60 std::sort(sorted.begin(), sorted.end(), [](const QQuickPopup *one, const QQuickPopup *another) {
61 return one->z() > another->z();
62 });
63 return sorted;
64}
65
66void QQuickOverlayPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
67{
68 updateGeometry();
69}
70
71void QQuickOverlayPrivate::itemRotationChanged(QQuickItem *)
72{
73 updateGeometry();
74}
75
76bool QQuickOverlayPrivate::startDrag(QEvent *event, const QPointF &pos)
77{
78 Q_Q(QQuickOverlay);
79 if (allDrawers.isEmpty())
80 return false;
81
82 // don't start dragging a drawer if a modal popup overlay is blocking (QTBUG-60602)
83 QQuickItem *item = q->childAt(pos.x(), pos.y());
84 if (item) {
85 const auto popups = stackingOrderPopups();
86 for (QQuickPopup *popup : popups) {
87 QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
88 if (p->dimmer == item && popup->isVisible() && popup->isModal())
89 return false;
90 }
91 }
92
93 const QList<QQuickPopup *> drawers = stackingOrderDrawers();
94 for (QQuickPopup *popup : drawers) {
95 QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup);
96 Q_ASSERT(drawer);
97 QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer);
98 if (p->startDrag(event)) {
99 setMouseGrabberPopup(drawer);
100 return true;
101 }
102 }
103
104 return false;
105}
106
107bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target)
108{
109 if (target) {
110 if (target->overlayEvent(source, event)) {
111 setMouseGrabberPopup(target);
112 return true;
113 }
114 return false;
115 }
116
117 switch (event->type()) {
118 default: {
119 if (mouseGrabberPopup)
120 break;
121#if QT_CONFIG(quicktemplates2_multitouch)
122 Q_FALLTHROUGH();
123 case QEvent::TouchBegin:
124 case QEvent::TouchUpdate:
125 case QEvent::TouchEnd:
126#endif
127 // allow non-modal popups to close themselves,
128 // and non-dimming modal popups to block the event
129 const auto popups = stackingOrderPopups();
130 for (QQuickPopup *popup : popups) {
131 if (popup->overlayEvent(source, event)) {
132 setMouseGrabberPopup(popup);
133 return true;
134 }
135 }
136 break;
137 }
138 }
139
140 event->ignore();
141 return false;
142}
143
144bool QQuickOverlayPrivate::handleMove(QQuickItem *source, QEvent *event, QQuickPopup *target)
145{
146 if (target)
147 return target->overlayEvent(source, event);
148 return false;
149}
150
151bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target)
152{
153 if (target) {
154 setMouseGrabberPopup(nullptr);
155 if (target->overlayEvent(source, event)) {
156 setMouseGrabberPopup(nullptr);
157 return true;
158 }
159 } else {
160 const auto popups = stackingOrderPopups();
161 for (QQuickPopup *popup : popups) {
162 if (popup->overlayEvent(source, event))
163 return true;
164 }
165 }
166 return false;
167}
168
169bool QQuickOverlayPrivate::handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target)
170{
171 switch (event->type()) {
172 case QEvent::MouseButtonPress:
173 if (!target && startDrag(event, event->scenePosition()))
174 return true;
175 return handlePress(source, event, target);
176 case QEvent::MouseMove:
177 return handleMove(source, event, target ? target : mouseGrabberPopup.data());
178 case QEvent::MouseButtonRelease:
179 return handleRelease(source, event, target ? target : mouseGrabberPopup.data());
180 default:
181 break;
182 }
183 return false;
184}
185
186bool QQuickOverlayPrivate::handleHoverEvent(QQuickItem *source, QHoverEvent *event, QQuickPopup *target)
187{
188 switch (event->type()) {
189 case QEvent::HoverEnter:
190 case QEvent::HoverMove:
191 case QEvent::HoverLeave:
192 if (target)
193 return target->overlayEvent(source, event);
194 return false;
195 default:
196 Q_UNREACHABLE(); // function must only be called on hover events
197 break;
198 }
199 return false;
200}
201
202#if QT_CONFIG(quicktemplates2_multitouch)
203bool QQuickOverlayPrivate::handleTouchEvent(QQuickItem *source, QTouchEvent *event, QQuickPopup *target)
204{
205 bool handled = false;
206 switch (event->type()) {
207 case QEvent::TouchBegin:
208 case QEvent::TouchUpdate:
209 case QEvent::TouchEnd:
210 for (const QTouchEvent::TouchPoint &point : event->points()) {
211 switch (point.state()) {
212 case QEventPoint::Pressed:
213 if (!target && startDrag(event, point.scenePosition()))
214 handled = true;
215 else
216 handled |= handlePress(source, event, target);
217 break;
218 case QEventPoint::Updated:
219 handled |= handleMove(source, event, target ? target : mouseGrabberPopup.data());
220 break;
221 case QEventPoint::Released:
222 handled |= handleRelease(source, event, target ? target : mouseGrabberPopup.data());
223 break;
224 default:
225 break;
226 }
227 }
228 break;
229
230 default:
231 break;
232 }
233
234 return handled;
235}
236#endif
237
238void QQuickOverlayPrivate::addPopup(QQuickPopup *popup)
239{
240 Q_Q(QQuickOverlay);
241 allPopups += popup;
242 if (QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup)) {
243 allDrawers += drawer;
244 q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty());
245 }
246}
247
248void QQuickOverlayPrivate::removePopup(QQuickPopup *popup)
249{
250 Q_Q(QQuickOverlay);
251 allPopups.removeOne(popup);
252 if (allDrawers.removeOne(popup))
253 q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty());
254}
255
256void QQuickOverlayPrivate::setMouseGrabberPopup(QQuickPopup *popup)
257{
258 if (popup && !popup->isVisible())
259 popup = nullptr;
260 mouseGrabberPopup = popup;
261}
262
263void QQuickOverlayPrivate::updateGeometry()
264{
265 Q_Q(QQuickOverlay);
266 if (!window || !window->contentItem())
267 return;
268
269 const QSizeF size = window->contentItem()->size();
270 const QPointF pos(-(size.width() - window->size().width()) / 2,
271 -(size.height() - window->size().height()) / 2);
272
273 q->setSize(size);
274 q->setPosition(pos);
275}
276
277QQuickOverlay::QQuickOverlay(QQuickItem *parent)
278 : QQuickItem(*(new QQuickOverlayPrivate), parent)
279{
280 Q_D(QQuickOverlay);
281 setZ(1000001); // DefaultWindowDecoration+1
282 setAcceptedMouseButtons(Qt::AllButtons);
283#if QT_CONFIG(quicktemplates2_multitouch)
284 setAcceptTouchEvents(true);
285#endif
286 setFiltersChildMouseEvents(true);
287 setVisible(false);
288
289 if (parent) {
290 d->updateGeometry();
291 QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry);
292 if (QQuickWindow *window = parent->window()) {
293 window->installEventFilter(this);
294 if (QQuickItem *contentItem = window->contentItem())
295 QQuickItemPrivate::get(contentItem)->addItemChangeListener(d, QQuickItemPrivate::Rotation);
296 }
297 }
298}
299
300QQuickOverlay::~QQuickOverlay()
301{
302 Q_D(QQuickOverlay);
303 if (QQuickItem *parent = parentItem()) {
304 QQuickItemPrivate::get(parent)->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
305 if (QQuickWindow *window = parent->window()) {
306 if (QQuickItem *contentItem = window->contentItem())
307 QQuickItemPrivate::get(contentItem)->removeItemChangeListener(d, QQuickItemPrivate::Rotation);
308 }
309 }
310}
311
312QQmlComponent *QQuickOverlay::modal() const
313{
314 Q_D(const QQuickOverlay);
315 return d->modal;
316}
317
318void QQuickOverlay::setModal(QQmlComponent *modal)
319{
320 Q_D(QQuickOverlay);
321 if (d->modal == modal)
322 return;
323
324 d->modal = modal;
325 emit modalChanged();
326}
327
328QQmlComponent *QQuickOverlay::modeless() const
329{
330 Q_D(const QQuickOverlay);
331 return d->modeless;
332}
333
334void QQuickOverlay::setModeless(QQmlComponent *modeless)
335{
336 Q_D(QQuickOverlay);
337 if (d->modeless == modeless)
338 return;
339
340 d->modeless = modeless;
341 emit modelessChanged();
342}
343
344QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window, QQuickItem *parent)
345{
346 if (!window)
347 return nullptr;
348
349 const char *name = "_q_QQuickOverlay";
350
351 if (QQuickItemPrivate::customOverlayRequested) {
352 while (parent) {
353 if (QQuickItemPrivate::get(parent)->customOverlay) {
354 QQuickOverlay *overlay = parent->property(name).value<QQuickOverlay *>();
355 if (!overlay) {
356 overlay = new QQuickOverlay(parent);
357 parent->setProperty(name, QVariant::fromValue(overlay));
358 }
359 return overlay;
360 }
361 parent = parent->parentItem();
362 }
363 }
364 QQuickOverlay *overlay = window->property(name).value<QQuickOverlay *>();
365 if (!overlay) {
366 QQuickItem *content = window->contentItem();
367 // Do not re-create the overlay if the window is being destroyed
368 // and thus, its content item no longer has a window associated.
369 if (content && content->window()) {
370 overlay = new QQuickOverlay(window->contentItem());
371 window->setProperty(name, QVariant::fromValue(overlay));
372 }
373 }
374 return overlay;
375}
376
377QQuickOverlayAttached *QQuickOverlay::qmlAttachedProperties(QObject *object)
378{
379 return new QQuickOverlayAttached(object);
380}
381
382void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data)
383{
384 Q_D(QQuickOverlay);
385 QQuickItem::itemChange(change, data);
386
387 if (change == ItemChildAddedChange || change == ItemChildRemovedChange) {
388 setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty());
389 if (data.item->parent() == d->mouseGrabberPopup)
390 d->setMouseGrabberPopup(nullptr);
391 }
392}
393
394void QQuickOverlay::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
395{
396 Q_D(QQuickOverlay);
397 QQuickItem::geometryChange(newGeometry, oldGeometry);
398 for (QQuickPopup *popup : std::as_const(d->allPopups))
399 QQuickPopupPrivate::get(popup)->resizeDimmer();
400}
401
402void QQuickOverlay::mousePressEvent(QMouseEvent *event)
403{
404 Q_D(QQuickOverlay);
405 d->handleMouseEvent(this, event);
406}
407
408void QQuickOverlay::mouseMoveEvent(QMouseEvent *event)
409{
410 Q_D(QQuickOverlay);
411 d->handleMouseEvent(this, event);
412}
413
414void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event)
415{
416 Q_D(QQuickOverlay);
417 d->handleMouseEvent(this, event);
418}
419
420#if QT_CONFIG(quicktemplates2_multitouch)
421void QQuickOverlay::touchEvent(QTouchEvent *event)
422{
423 Q_D(QQuickOverlay);
424 d->handleTouchEvent(this, event);
425}
426#endif
427
428#if QT_CONFIG(wheelevent)
429void QQuickOverlay::wheelEvent(QWheelEvent *event)
430{
431 Q_D(QQuickOverlay);
432 if (d->mouseGrabberPopup) {
433 d->mouseGrabberPopup->overlayEvent(this, event);
434 return;
435 } else {
436 const auto popups = d->stackingOrderPopups();
437 for (QQuickPopup *popup : popups) {
438 if (popup->overlayEvent(this, event))
439 return;
440 }
441 }
442 event->ignore();
443}
444#endif
445
446/*!
447 \internal
448
449 When clicking inside a scene with a single active popup, a few things can happen.
450 The click can be inside the popup item, in which case, we stop filtering to allow
451 normal event handling. Or the click can be outside the popup, in which case,
452 it will normally be inside the overlay, or the popup's dimmer item.
453
454 When dealing with nested popups, the second popup's dimmer (or popupItem if the dimmer is absent)
455 will become an exclusive grabber to the pointerEvent, during childMouseEventFilter.
456 (sometimes the overlay becomes the exclusive grabber instead, why?).
457*/
458bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
459{
460 Q_D(QQuickOverlay);
461 const auto popups = d->stackingOrderPopups();
462 for (QQuickPopup *popup : popups) {
463 QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
464
465 // Stop filtering overlay events when reaching a popup item or an item
466 // that is inside the popup. Let the popup content handle its events.
467 if (item == p->popupItem || p->popupItem->isAncestorOf(item))
468 break;
469
470 // Let the popup try closing itself when pressing or releasing over its
471 // background dimming OR over another popup underneath, in case the popup
472 // does not have background dimming.
473 if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) {
474 bool handled = false;
475 switch (event->type()) {
476#if QT_CONFIG(quicktemplates2_multitouch)
477 case QEvent::TouchBegin:
478 case QEvent::TouchUpdate:
479 case QEvent::TouchEnd:
480 handled = d->handleTouchEvent(item, static_cast<QTouchEvent *>(event), popup);
481 break;
482#endif
483 case QEvent::HoverEnter:
484 case QEvent::HoverMove:
485 case QEvent::HoverLeave:
486 // If the control item has already been hovered, allow the hover leave event
487 // to be processed by the same item for resetting its internal hovered state
488 // instead of filtering it here.
489 if (auto *control = qobject_cast<QQuickControl *>(item)) {
490 if (control->isHovered() && event->type() == QEvent::HoverLeave)
491 return false;
492 }
493 handled = d->handleHoverEvent(item, static_cast<QHoverEvent *>(event), popup);
494 break;
495
496 case QEvent::MouseButtonPress:
497 case QEvent::MouseMove:
498 case QEvent::MouseButtonRelease:
499 handled = d->handleMouseEvent(item, static_cast<QMouseEvent *>(event), popup);
500 break;
501
502 default:
503 break;
504 }
505 if (handled)
506 return true;
507 }
508 }
509 return false;
510}
511
512/*!
513 \internal
514
515 The overlay installs itself as an event filter on the window it belongs to.
516 It will filter Touch, Mouse (press and release) and Wheel related events.
517
518 Touch and MousePress events will be passed to the delivery agent for normal event propagation,
519 where they will be filtered by the overlay again in QQuickOverlay::childMouseEventFilter.
520 All opened popups will then be iterated, to check if the event should close the popup or not.
521 Also modality is checked to determine the return type, which will cause the delivery agent to
522 continue normal propagation in this second childMouseEventFilter filtering step.
523
524 The reason for installing the eventFilter is to allow non-modal popups with CloseOnReleaseOutside
525 as the closing policy to close when clicking the overlay. The delivery agent won't send the
526 release event to the overlay when clicking it directly, only the press event.
527*/
528bool QQuickOverlay::eventFilter(QObject *object, QEvent *event)
529{
530 Q_D(QQuickOverlay);
531 if (!isVisible() || object != d->window)
532 return false;
533
534 switch (event->type()) {
535#if QT_CONFIG(quicktemplates2_multitouch)
536 case QEvent::TouchBegin:
537 case QEvent::TouchUpdate:
538 case QEvent::TouchEnd:
539 if (static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Pressed)
540 emit pressed();
541 if (static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Released)
542 emit released();
543
544 // allow non-modal popups to close on touch release outside
545 if (!d->mouseGrabberPopup) {
546 QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
547 for (const QTouchEvent::TouchPoint &point : touchEvent->points()) {
548 if (point.state() == QEventPoint::Released) {
549 QQuickDeliveryAgentPrivate::translateTouchEvent(touchEvent);
550 if (d->handleRelease(d->window->contentItem(), event, nullptr))
551 break;
552 }
553 }
554 }
555
556 // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
557 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
558 d->deliveryAgentPrivate()->handleTouchEvent(static_cast<QTouchEvent *>(event));
559 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
560
561 // If a touch event hasn't been accepted after being delivered, there
562 // were no items interested in touch events at any of the touch points.
563 // Make sure to accept the touch event in order to receive the consequent
564 // touch events, to be able to close non-modal popups on release outside.
565 event->accept();
566 // Since we eat the event, QQuickWindow::event never sees it to clean up the
567 // grabber states. So we have to do so explicitly.
568 d->deliveryAgentPrivate()->clearGrabbers(static_cast<QPointerEvent *>(event));
569 return true;
570#endif
571
572 case QEvent::MouseButtonPress: {
573 auto *mouseEvent = static_cast<QMouseEvent *>(event);
574 // Don't filter right mouse button clicks, as it prevents ContextMenu from
575 // receiving QContextMenuEvents as long as e.g. a Drawer exists, even if it's not visible.
576 // This does not prevent popups from being closed with the right mouse button,
577 // as mousePressEvent takes care of that.
578 if (mouseEvent->button() == Qt::RightButton)
579 break;
580
581#if QT_CONFIG(quicktemplates2_multitouch)
582 // do not emit pressed() twice when mouse events have been synthesized from touch events
583 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
584#endif
585 emit pressed();
586
587 // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
588 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
589 d->deliveryAgentPrivate()->handleMouseEvent(mouseEvent);
590 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
591
592 // If a mouse event hasn't been accepted after being delivered, there
593 // was no item interested in mouse events at the mouse point. Make sure
594 // to accept the mouse event in order to receive the consequent mouse
595 // events, to be able to close non-modal popups on release outside.
596 event->accept();
597 return true;
598 }
599 case QEvent::MouseButtonRelease: {
600 auto *mouseEvent = static_cast<QMouseEvent *>(event);
601 if (mouseEvent->button() == Qt::RightButton)
602 break;
603
604#if QT_CONFIG(quicktemplates2_multitouch)
605 // do not emit released() twice when mouse events have been synthesized from touch events
606 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
607#endif
608 emit released();
609
610 // allow non-modal popups to close on mouse release outside
611 if (!d->mouseGrabberPopup)
612 d->handleRelease(d->window->contentItem(), event, nullptr);
613 break;
614 }
615#if QT_CONFIG(wheelevent)
616 case QEvent::Wheel: {
617 // If the top item in the drawing-order is blocked by a modal popup, then
618 // eat the event. There is no scenario where the top most item is blocked
619 // by a popup, but an item further down in the drawing order is not.
620 QWheelEvent *we = static_cast<QWheelEvent *>(event);
621 const QList<QQuickItem *> targetItems = d->deliveryAgentPrivate()->pointerTargets(
622 d->window->contentItem(), we, we->point(0), false, false);
623 if (targetItems.isEmpty())
624 break;
625
626 QQuickItem * const dimmerItem = property("_q_dimmerItem").value<QQuickItem *>();
627 QQuickItem * const topItem = targetItems.first();
628
629 QQuickItem *item = topItem;
630 while ((item = item->parentItem())) {
631 if (qobject_cast<QQuickPopupItem *>(item))
632 break;
633 }
634
635 if (!item && dimmerItem != topItem && isAncestorOf(topItem))
636 break;
637
638 const auto popups = d->stackingOrderPopups();
639 // Eat the event if receiver topItem is not a child of a popup before
640 // the first modal popup.
641 for (const auto &popup : popups) {
642 const QQuickItem *popupItem = popup->popupItem();
643 if (!popupItem)
644 continue;
645 // if current popup item matches with any popup in stack, deliver the event
646 if (popupItem == item)
647 break;
648 // if the popup doesn't contain the item but is modal, eat the event
649 if (popup->overlayEvent(topItem, we))
650 return true;
651 }
652 break;
653 }
654#endif
655
656 default:
657 break;
658 }
659
660 return false;
661}
662
664{
665public:
666 Q_DECLARE_PUBLIC(QQuickOverlayAttached)
667
669 void setWindowAndParent(QQuickWindow *newWindow, QQuickItem *parent);
670
672 QQmlComponent *modal = nullptr;
673 QQmlComponent *modeless = nullptr;
675};
676
677void QQuickOverlayAttachedPrivate::setWindow(QQuickWindow *newWindow)
678{
679 setWindowAndParent(newWindow, parentItem);
680}
681
682void QQuickOverlayAttachedPrivate::setWindowAndParent(QQuickWindow *newWindow, QQuickItem *parent)
683{
684 Q_Q(QQuickOverlayAttached);
685 if (window == newWindow)
686 return;
687
688 if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window, parent)) {
689 QObject::disconnect(oldOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
690 QObject::disconnect(oldOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
691 }
692
693 if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(newWindow, parent)) {
694 QObject::connect(newOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
695 QObject::connect(newOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
696 }
697
698 window = newWindow;
699 if (parent)
700 parentItem = parent;
701 emit q->overlayChanged();
702}
703
704/*!
705 \qmlattachedsignal QtQuick.Controls::Overlay::pressed()
706
707 This attached signal is emitted when the overlay is pressed by the user while
708 a popup is visible.
709
710 The signal can be attached to any item, popup, or window. When attached to an
711 item or a popup, the signal is only emitted if the item or popup is in a window.
712
713 \include qquickoverlay-pressed-released.qdocinc
714*/
715
716/*!
717 \qmlattachedsignal QtQuick.Controls::Overlay::released()
718
719 This attached signal is emitted when the overlay is released by the user while
720 a popup is visible.
721
722 The signal can be attached to any item, popup, or window. When attached to an
723 item or a popup, the signal is only emitted if the item or popup is in a window.
724
725 \include qquickoverlay-pressed-released.qdocinc
726*/
727
728QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent)
729 : QObject(*(new QQuickOverlayAttachedPrivate), parent)
730{
731 Q_D(QQuickOverlayAttached);
732 if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
733 d->setWindowAndParent(item->window(), item);
734 QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
735 } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
736 d->setWindowAndParent(popup->window(), popup->parentItem());
737 QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
738 } else {
739 d->setWindow(qobject_cast<QQuickWindow *>(parent));
740 }
741}
742
743/*!
744 \qmlattachedproperty Overlay QtQuick.Controls::Overlay::overlay
745 \readonly
746
747 This attached property holds the window overlay item.
748
749 The property can be attached to any item, popup, or window. When attached to an
750 item or a popup, the value is \c null if the item or popup is not in a window.
751*/
752QQuickOverlay *QQuickOverlayAttached::overlay() const
753{
754 Q_D(const QQuickOverlayAttached);
755 return QQuickOverlay::overlay(d->window, d->parentItem);
756}
757
758/*!
759 \qmlattachedproperty Component QtQuick.Controls::Overlay::modal
760
761 This attached property holds a component to use as a visual item that implements
762 background dimming for modal popups. It is created for and stacked below visible
763 modal popups.
764
765 The property can be attached to any popup.
766
767 For example, to change the color of the background dimming for a modal
768 popup, the following code can be used:
769
770 \snippet qtquickcontrols-overlay-modal.qml 1
771
772 \sa Popup::modal
773*/
774QQmlComponent *QQuickOverlayAttached::modal() const
775{
776 Q_D(const QQuickOverlayAttached);
777 return d->modal;
778}
779
780void QQuickOverlayAttached::setModal(QQmlComponent *modal)
781{
782 Q_D(QQuickOverlayAttached);
783 if (d->modal == modal)
784 return;
785
786 d->modal = modal;
787 emit modalChanged();
788}
789
790/*!
791 \qmlattachedproperty Component QtQuick.Controls::Overlay::modeless
792
793 This attached property holds a component to use as a visual item that implements
794 background dimming for modeless popups. It is created for and stacked below visible
795 dimming popups.
796
797 The property can be attached to any popup.
798
799 For example, to change the color of the background dimming for a modeless
800 popup, the following code can be used:
801
802 \snippet qtquickcontrols-overlay-modeless.qml 1
803
804 \sa Popup::dim
805*/
806QQmlComponent *QQuickOverlayAttached::modeless() const
807{
808 Q_D(const QQuickOverlayAttached);
809 return d->modeless;
810}
811
812void QQuickOverlayAttached::setModeless(QQmlComponent *modeless)
813{
814 Q_D(QQuickOverlayAttached);
815 if (d->modeless == modeless)
816 return;
817
818 d->modeless = modeless;
819 emit modelessChanged();
820}
821
822QT_END_NAMESPACE
823
824#include "moc_qquickoverlay_p.cpp"
void setWindowAndParent(QQuickWindow *newWindow, QQuickItem *parent)