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 QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
533 for (const QTouchEvent::TouchPoint &point : touchEvent->points()) {
534 if (point.state() == QEventPoint::Released) {
535 QQuickDeliveryAgentPrivate::translateTouchEvent(touchEvent);
536 if (d->handleRelease(d->window->contentItem(), event, nullptr))
537 break;
538 }
539 }
540 }
541
542 // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
543 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
544 d->deliveryAgentPrivate()->handleTouchEvent(static_cast<QTouchEvent *>(event));
545 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
546
547 // If a touch event hasn't been accepted after being delivered, there
548 // were no items interested in touch events at any of the touch points.
549 // Make sure to accept the touch event in order to receive the consequent
550 // touch events, to be able to close non-modal popups on release outside.
551 event->accept();
552 // Since we eat the event, QQuickWindow::event never sees it to clean up the
553 // grabber states. So we have to do so explicitly.
554 d->deliveryAgentPrivate()->clearGrabbers(static_cast<QPointerEvent *>(event));
555 return true;
556#endif
557
558 case QEvent::MouseButtonPress: {
559 auto *mouseEvent = static_cast<QMouseEvent *>(event);
560 // Don't filter right mouse button clicks, as it prevents ContextMenu from
561 // receiving QContextMenuEvents as long as e.g. a Drawer exists, even if it's not visible.
562 // This does not prevent popups from being closed with the right mouse button,
563 // as mousePressEvent takes care of that.
564 if (mouseEvent->button() == Qt::RightButton)
565 break;
566
567#if QT_CONFIG(quicktemplates2_multitouch)
568 // do not emit pressed() twice when mouse events have been synthesized from touch events
569 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
570#endif
571 emit pressed();
572
573 // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
574 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = d->deliveryAgent();
575 d->deliveryAgentPrivate()->handleMouseEvent(mouseEvent);
576 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
577
578 // If a mouse event hasn't been accepted after being delivered, there
579 // was no item interested in mouse events at the mouse point. Make sure
580 // to accept the mouse event in order to receive the consequent mouse
581 // events, to be able to close non-modal popups on release outside.
582 event->accept();
583 return true;
584 }
585 case QEvent::MouseButtonRelease: {
586 auto *mouseEvent = static_cast<QMouseEvent *>(event);
587 if (mouseEvent->button() == Qt::RightButton)
588 break;
589
590#if QT_CONFIG(quicktemplates2_multitouch)
591 // do not emit released() twice when mouse events have been synthesized from touch events
592 if (mouseEvent->source() == Qt::MouseEventNotSynthesized)
593#endif
594 emit released();
595
596 // allow non-modal popups to close on mouse release outside
597 if (!d->mouseGrabberPopup)
598 d->handleRelease(d->window->contentItem(), event, nullptr);
599 break;
600 }
601#if QT_CONFIG(wheelevent)
602 case QEvent::Wheel: {
603 // If the top item in the drawing-order is blocked by a modal popup, then
604 // eat the event. There is no scenario where the top most item is blocked
605 // by a popup, but an item further down in the drawing order is not.
606 QWheelEvent *we = static_cast<QWheelEvent *>(event);
607 const QVector<QQuickItem *> targetItems = d->deliveryAgentPrivate()->pointerTargets(
608 d->window->contentItem(), we, we->point(0), false, false);
609 if (targetItems.isEmpty())
610 break;
611
612 QQuickItem * const dimmerItem = property("_q_dimmerItem").value<QQuickItem *>();
613 QQuickItem * const topItem = targetItems.first();
614
615 QQuickItem *item = topItem;
616 while ((item = item->parentItem())) {
617 if (qobject_cast<QQuickPopupItem *>(item))
618 break;
619 }
620
621 if (!item && dimmerItem != topItem && isAncestorOf(topItem))
622 break;
623
624 const auto popups = d->stackingOrderPopups();
625 // Eat the event if receiver topItem is not a child of a popup before
626 // the first modal popup.
627 for (const auto &popup : popups) {
628 const QQuickItem *popupItem = popup->popupItem();
629 if (!popupItem)
630 continue;
631 // if current popup item matches with any popup in stack, deliver the event
632 if (popupItem == item)
633 break;
634 // if the popup doesn't contain the item but is modal, eat the event
635 if (popup->overlayEvent(topItem, we))
636 return true;
637 }
638 break;
639 }
640#endif
641
642 default:
643 break;
644 }
645
646 return false;
647}
648
650{
651public:
652 Q_DECLARE_PUBLIC(QQuickOverlayAttached)
653
655
657 QQmlComponent *modal = nullptr;
658 QQmlComponent *modeless = nullptr;
659};
660
661void QQuickOverlayAttachedPrivate::setWindow(QQuickWindow *newWindow)
662{
663 Q_Q(QQuickOverlayAttached);
664 if (window == newWindow)
665 return;
666
667 if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window)) {
668 QObject::disconnect(oldOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
669 QObject::disconnect(oldOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
670 }
671
672 if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(newWindow)) {
673 QObject::connect(newOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
674 QObject::connect(newOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
675 }
676
677 window = newWindow;
678 emit q->overlayChanged();
679}
680
681/*!
682 \qmlattachedsignal QtQuick.Controls::Overlay::pressed()
683
684 This attached signal is emitted when the overlay is pressed by the user while
685 a popup is visible.
686
687 The signal can be attached to any item, popup, or window. When attached to an
688 item or a popup, the signal is only emitted if the item or popup is in a window.
689
690 \include qquickoverlay-pressed-released.qdocinc
691*/
692
693/*!
694 \qmlattachedsignal QtQuick.Controls::Overlay::released()
695
696 This attached signal is emitted when the overlay is released by the user while
697 a popup is visible.
698
699 The signal can be attached to any item, popup, or window. When attached to an
700 item or a popup, the signal is only emitted if the item or popup is in a window.
701
702 \include qquickoverlay-pressed-released.qdocinc
703*/
704
705QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent)
706 : QObject(*(new QQuickOverlayAttachedPrivate), parent)
707{
708 Q_D(QQuickOverlayAttached);
709 if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
710 d->setWindow(item->window());
711 QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
712 } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
713 d->setWindow(popup->window());
714 QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
715 } else {
716 d->setWindow(qobject_cast<QQuickWindow *>(parent));
717 }
718}
719
720/*!
721 \qmlattachedproperty Overlay QtQuick.Controls::Overlay::overlay
722 \readonly
723
724 This attached property holds the window overlay item.
725
726 The property can be attached to any item, popup, or window. When attached to an
727 item or a popup, the value is \c null if the item or popup is not in a window.
728*/
729QQuickOverlay *QQuickOverlayAttached::overlay() const
730{
731 Q_D(const QQuickOverlayAttached);
732 return QQuickOverlay::overlay(d->window);
733}
734
735/*!
736 \qmlattachedproperty Component QtQuick.Controls::Overlay::modal
737
738 This attached property holds a component to use as a visual item that implements
739 background dimming for modal popups. It is created for and stacked below visible
740 modal popups.
741
742 The property can be attached to any popup.
743
744 For example, to change the color of the background dimming for a modal
745 popup, the following code can be used:
746
747 \snippet qtquickcontrols-overlay-modal.qml 1
748
749 \sa Popup::modal
750*/
751QQmlComponent *QQuickOverlayAttached::modal() const
752{
753 Q_D(const QQuickOverlayAttached);
754 return d->modal;
755}
756
757void QQuickOverlayAttached::setModal(QQmlComponent *modal)
758{
759 Q_D(QQuickOverlayAttached);
760 if (d->modal == modal)
761 return;
762
763 d->modal = modal;
764 emit modalChanged();
765}
766
767/*!
768 \qmlattachedproperty Component QtQuick.Controls::Overlay::modeless
769
770 This attached property holds a component to use as a visual item that implements
771 background dimming for modeless popups. It is created for and stacked below visible
772 dimming popups.
773
774 The property can be attached to any popup.
775
776 For example, to change the color of the background dimming for a modeless
777 popup, the following code can be used:
778
779 \snippet qtquickcontrols-overlay-modeless.qml 1
780
781 \sa Popup::dim
782*/
783QQmlComponent *QQuickOverlayAttached::modeless() const
784{
785 Q_D(const QQuickOverlayAttached);
786 return d->modeless;
787}
788
789void QQuickOverlayAttached::setModeless(QQmlComponent *modeless)
790{
791 Q_D(QQuickOverlayAttached);
792 if (d->modeless == modeless)
793 return;
794
795 d->modeless = modeless;
796 emit modelessChanged();
797}
798
799QT_END_NAMESPACE
800
801#include "moc_qquickoverlay_p.cpp"