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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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