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)
345{
346 if (!window)
347 return nullptr;
348
349 const char *name = "_q_QQuickOverlay";
350 QQuickOverlay *overlay = window->property(name).value<QQuickOverlay *>();
351 if (!overlay) {
352 QQuickItem *content = window->contentItem();
353 // Do not re-create the overlay if the window is being destroyed
354 // and thus, its content item no longer has a window associated.
355 if (content && content->window()) {
356 overlay = new QQuickOverlay(window->contentItem());
357 window->setProperty(name, QVariant::fromValue(overlay));
358 }
359 }
360 return overlay;
361}
362
363QQuickOverlayAttached *QQuickOverlay::qmlAttachedProperties(QObject *object)
364{
365 return new QQuickOverlayAttached(object);
366}
367
368void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data)
369{
370 Q_D(QQuickOverlay);
371 QQuickItem::itemChange(change, data);
372
373 if (change == ItemChildAddedChange || change == ItemChildRemovedChange) {
374 setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty());
375 if (data.item->parent() == d->mouseGrabberPopup)
376 d->setMouseGrabberPopup(nullptr);
377 }
378}
379
380void QQuickOverlay::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
381{
382 Q_D(QQuickOverlay);
383 QQuickItem::geometryChange(newGeometry, oldGeometry);
384 for (QQuickPopup *popup : std::as_const(d->allPopups))
385 QQuickPopupPrivate::get(popup)->resizeDimmer();
386}
387
388void QQuickOverlay::mousePressEvent(QMouseEvent *event)
389{
390 Q_D(QQuickOverlay);
391 d->handleMouseEvent(this, event);
392}
393
394void QQuickOverlay::mouseMoveEvent(QMouseEvent *event)
395{
396 Q_D(QQuickOverlay);
397 d->handleMouseEvent(this, event);
398}
399
400void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event)
401{
402 Q_D(QQuickOverlay);
403 d->handleMouseEvent(this, event);
404}
405
406#if QT_CONFIG(quicktemplates2_multitouch)
407void QQuickOverlay::touchEvent(QTouchEvent *event)
408{
409 Q_D(QQuickOverlay);
410 d->handleTouchEvent(this, event);
411}
412#endif
413
414#if QT_CONFIG(wheelevent)
415void QQuickOverlay::wheelEvent(QWheelEvent *event)
416{
417 Q_D(QQuickOverlay);
418 if (d->mouseGrabberPopup) {
419 d->mouseGrabberPopup->overlayEvent(this, event);
420 return;
421 } else {
422 const auto popups = d->stackingOrderPopups();
423 for (QQuickPopup *popup : popups) {
424 if (popup->overlayEvent(this, event))
425 return;
426 }
427 }
428 event->ignore();
429}
430#endif
431
432/*!
433 \internal
434
435 When clicking inside a scene with a single active popup, a few things can happen.
436 The click can be inside the popup item, in which case, we stop filtering to allow
437 normal event handling. Or the click can be outside the popup, in which case,
438 it will normally be inside the overlay, or the popup's dimmer item.
439
440 When dealing with nested popups, the second popup's dimmer (or popupItem if the dimmer is absent)
441 will become an exclusive grabber to the pointerEvent, during childMouseEventFilter.
442 (sometimes the overlay becomes the exclusive grabber instead, why?).
443*/
444bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
445{
446 Q_D(QQuickOverlay);
447 const auto popups = d->stackingOrderPopups();
448 for (QQuickPopup *popup : popups) {
449 QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
450
451 // Stop filtering overlay events when reaching a popup item or an item
452 // that is inside the popup. Let the popup content handle its events.
453 if (item == p->popupItem || p->popupItem->isAncestorOf(item))
454 break;
455
456 // Let the popup try closing itself when pressing or releasing over its
457 // background dimming OR over another popup underneath, in case the popup
458 // does not have background dimming.
459 if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) {
460 bool handled = false;
461 switch (event->type()) {
462#if QT_CONFIG(quicktemplates2_multitouch)
463 case QEvent::TouchBegin:
464 case QEvent::TouchUpdate:
465 case QEvent::TouchEnd:
466 handled = d->handleTouchEvent(item, static_cast<QTouchEvent *>(event), popup);
467 break;
468#endif
469 case QEvent::HoverEnter:
470 case QEvent::HoverMove:
471 case QEvent::HoverLeave:
472 // If the control item has already been hovered, allow the hover leave event
473 // to be processed by the same item for resetting its internal hovered state
474 // instead of filtering it here.
475 if (auto *control = qobject_cast<QQuickControl *>(item)) {
476 if (control->isHovered() && event->type() == QEvent::HoverLeave)
477 return false;
478 }
479 handled = d->handleHoverEvent(item, static_cast<QHoverEvent *>(event), popup);
480 break;
481
482 case QEvent::MouseButtonPress:
483 case QEvent::MouseMove:
484 case QEvent::MouseButtonRelease:
485 handled = d->handleMouseEvent(item, static_cast<QMouseEvent *>(event), popup);
486 break;
487
488 default:
489 break;
490 }
491 if (handled)
492 return true;
493 }
494 }
495 return false;
496}
497
498/*!
499 \internal
500
501 The overlay installs itself as an event filter on the window it belongs to.
502 It will filter Touch, Mouse (press and release) and Wheel related events.
503
504 Touch and MousePress events will be passed to the delivery agent for normal event propagation,
505 where they will be filtered by the overlay again in QQuickOverlay::childMouseEventFilter.
506 All opened popups will then be iterated, to check if the event should close the popup or not.
507 Also modality is checked to determine the return type, which will cause the delivery agent to
508 continue normal propagation in this second childMouseEventFilter filtering step.
509
510 The reason for installing the eventFilter is to allow non-modal popups with CloseOnReleaseOutside
511 as the closing policy to close when clicking the overlay. The delivery agent won't send the
512 release event to the overlay when clicking it directly, only the press event.
513*/
514bool QQuickOverlay::eventFilter(QObject *object, QEvent *event)
515{
516 Q_D(QQuickOverlay);
517 if (!isVisible() || object != d->window)
518 return false;
519
520 switch (event->type()) {
521#if QT_CONFIG(quicktemplates2_multitouch)
522 case QEvent::TouchBegin:
523 case QEvent::TouchUpdate:
524 case QEvent::TouchEnd:
525 if (static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Pressed)
526 emit pressed();
527 if (static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Released)
528 emit released();
529
530 // allow non-modal popups to close on touch release outside
531 if (!d->mouseGrabberPopup) {
532 for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->points()) {
533 if (point.state() == QEventPoint::Released) {
534 if (d->handleRelease(d->window->contentItem(), event, nullptr))
535 break;
536 }
537 }
538 }
539
540 // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
541 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
542 d->deliveryAgentPrivate()->handleTouchEvent(static_cast<QTouchEvent *>(event));
543 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
544
545 // If a touch event hasn't been accepted after being delivered, there
546 // were no items interested in touch events at any of the touch points.
547 // Make sure to accept the touch event in order to receive the consequent
548 // touch events, to be able to close non-modal popups on release outside.
549 event->accept();
550 // Since we eat the event, QQuickWindow::event never sees it to clean up the
551 // grabber states. So we have to do so explicitly.
552 d->deliveryAgentPrivate()->clearGrabbers(static_cast<QPointerEvent *>(event));
553 return true;
554#endif
555
556 case QEvent::MouseButtonPress: {
557 auto *mouseEvent = static_cast<QMouseEvent *>(event);
558 // Don't filter right mouse button clicks, as it prevents ContextMenu from
559 // receiving QContextMenuEvents as long as e.g. a Drawer exists, even if it's not visible.
560 // This does not prevent popups from being closed with the right mouse button,
561 // as mousePressEvent takes care of that.
562 if (mouseEvent->button() == Qt::RightButton)
563 break;
564
565#if QT_CONFIG(quicktemplates2_multitouch)
566 // do not emit pressed() twice when mouse events have been synthesized from touch events
567 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
568#endif
569 emit pressed();
570
571 // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
572 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
573 d->deliveryAgentPrivate()->handleMouseEvent(mouseEvent);
574 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
575
576 // If a mouse event hasn't been accepted after being delivered, there
577 // was no item interested in mouse events at the mouse point. Make sure
578 // to accept the mouse event in order to receive the consequent mouse
579 // events, to be able to close non-modal popups on release outside.
580 event->accept();
581 return true;
582 }
583 case QEvent::MouseButtonRelease: {
584 auto *mouseEvent = static_cast<QMouseEvent *>(event);
585 if (mouseEvent->button() == Qt::RightButton)
586 break;
587
588#if QT_CONFIG(quicktemplates2_multitouch)
589 // do not emit released() twice when mouse events have been synthesized from touch events
590 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
591#endif
592 emit released();
593
594 // allow non-modal popups to close on mouse release outside
595 if (!d->mouseGrabberPopup)
596 d->handleRelease(d->window->contentItem(), event, nullptr);
597 break;
598 }
599#if QT_CONFIG(wheelevent)
600 case QEvent::Wheel: {
601 // If the top item in the drawing-order is blocked by a modal popup, then
602 // eat the event. There is no scenario where the top most item is blocked
603 // by a popup, but an item further down in the drawing order is not.
604 QWheelEvent *we = static_cast<QWheelEvent *>(event);
605 const QVector<QQuickItem *> targetItems = d->deliveryAgentPrivate()->pointerTargets(
606 d->window->contentItem(), we, we->point(0), false, false);
607 if (targetItems.isEmpty())
608 break;
609
610 QQuickItem * const dimmerItem = property("_q_dimmerItem").value<QQuickItem *>();
611 QQuickItem * const topItem = targetItems.first();
612
613 QQuickItem *item = topItem;
614 while ((item = item->parentItem())) {
615 if (qobject_cast<QQuickPopupItem *>(item))
616 break;
617 }
618
619 if (!item && dimmerItem != topItem && isAncestorOf(topItem))
620 break;
621
622 const auto popups = d->stackingOrderPopups();
623 // Eat the event if receiver topItem is not a child of a popup before
624 // the first modal popup.
625 for (const auto &popup : popups) {
626 const QQuickItem *popupItem = popup->popupItem();
627 if (!popupItem)
628 continue;
629 // if current popup item matches with any popup in stack, deliver the event
630 if (popupItem == item)
631 break;
632 // if the popup doesn't contain the item but is modal, eat the event
633 if (popup->overlayEvent(topItem, we))
634 return true;
635 }
636 break;
637 }
638#endif
639
640 default:
641 break;
642 }
643
644 return false;
645}
646
648{
649public:
650 Q_DECLARE_PUBLIC(QQuickOverlayAttached)
651
653
655 QQmlComponent *modal = nullptr;
656 QQmlComponent *modeless = nullptr;
657};
658
659void QQuickOverlayAttachedPrivate::setWindow(QQuickWindow *newWindow)
660{
661 Q_Q(QQuickOverlayAttached);
662 if (window == newWindow)
663 return;
664
665 if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window)) {
666 QObject::disconnect(oldOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
667 QObject::disconnect(oldOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
668 }
669
670 if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(newWindow)) {
671 QObject::connect(newOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
672 QObject::connect(newOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
673 }
674
675 window = newWindow;
676 emit q->overlayChanged();
677}
678
679/*!
680 \qmlattachedsignal QtQuick.Controls::Overlay::pressed()
681
682 This attached signal is emitted when the overlay is pressed by the user while
683 a popup is visible.
684
685 The signal can be attached to any item, popup, or window. When attached to an
686 item or a popup, the signal is only emitted if the item or popup is in a window.
687
688 \include qquickoverlay-pressed-released.qdocinc
689*/
690
691/*!
692 \qmlattachedsignal QtQuick.Controls::Overlay::released()
693
694 This attached signal is emitted when the overlay is released by the user while
695 a popup is visible.
696
697 The signal can be attached to any item, popup, or window. When attached to an
698 item or a popup, the signal is only emitted if the item or popup is in a window.
699
700 \include qquickoverlay-pressed-released.qdocinc
701*/
702
703QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent)
704 : QObject(*(new QQuickOverlayAttachedPrivate), parent)
705{
706 Q_D(QQuickOverlayAttached);
707 if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
708 d->setWindow(item->window());
709 QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
710 } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
711 d->setWindow(popup->window());
712 QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
713 } else {
714 d->setWindow(qobject_cast<QQuickWindow *>(parent));
715 }
716}
717
718/*!
719 \qmlattachedproperty Overlay QtQuick.Controls::Overlay::overlay
720 \readonly
721
722 This attached property holds the window overlay item.
723
724 The property can be attached to any item, popup, or window. When attached to an
725 item or a popup, the value is \c null if the item or popup is not in a window.
726*/
727QQuickOverlay *QQuickOverlayAttached::overlay() const
728{
729 Q_D(const QQuickOverlayAttached);
730 return QQuickOverlay::overlay(d->window);
731}
732
733/*!
734 \qmlattachedproperty Component QtQuick.Controls::Overlay::modal
735
736 This attached property holds a component to use as a visual item that implements
737 background dimming for modal popups. It is created for and stacked below visible
738 modal popups.
739
740 The property can be attached to any popup.
741
742 For example, to change the color of the background dimming for a modal
743 popup, the following code can be used:
744
745 \snippet qtquickcontrols-overlay-modal.qml 1
746
747 \sa Popup::modal
748*/
749QQmlComponent *QQuickOverlayAttached::modal() const
750{
751 Q_D(const QQuickOverlayAttached);
752 return d->modal;
753}
754
755void QQuickOverlayAttached::setModal(QQmlComponent *modal)
756{
757 Q_D(QQuickOverlayAttached);
758 if (d->modal == modal)
759 return;
760
761 d->modal = modal;
762 emit modalChanged();
763}
764
765/*!
766 \qmlattachedproperty Component QtQuick.Controls::Overlay::modeless
767
768 This attached property holds a component to use as a visual item that implements
769 background dimming for modeless popups. It is created for and stacked below visible
770 dimming popups.
771
772 The property can be attached to any popup.
773
774 For example, to change the color of the background dimming for a modeless
775 popup, the following code can be used:
776
777 \snippet qtquickcontrols-overlay-modeless.qml 1
778
779 \sa Popup::dim
780*/
781QQmlComponent *QQuickOverlayAttached::modeless() const
782{
783 Q_D(const QQuickOverlayAttached);
784 return d->modeless;
785}
786
787void QQuickOverlayAttached::setModeless(QQmlComponent *modeless)
788{
789 Q_D(QQuickOverlayAttached);
790 if (d->modeless == modeless)
791 return;
792
793 d->modeless = modeless;
794 emit modelessChanged();
795}
796
797QT_END_NAMESPACE
798
799#include "moc_qquickoverlay_p.cpp"