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

source code of qtdeclarative/src/quicktemplates/qquickoverlay.cpp