1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include "qquickcontrol_p_p.h" |
38 | #include "qquickoverlay_p.h" |
39 | #include "qquickoverlay_p_p.h" |
40 | #include "qquickpopupitem_p_p.h" |
41 | #include "qquickpopup_p_p.h" |
42 | #include "qquickdrawer_p.h" |
43 | #include "qquickdrawer_p_p.h" |
44 | #include "qquickapplicationwindow_p.h" |
45 | #include <QtQml/qqmlinfo.h> |
46 | #include <QtQml/qqmlproperty.h> |
47 | #include <QtQml/qqmlcomponent.h> |
48 | #include <algorithm> |
49 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | /*! |
53 | \qmltype Overlay |
54 | \inherits Item |
55 | //! \instantiates QQuickOverlay |
56 | \inqmlmodule QtQuick.Controls |
57 | \since 5.10 |
58 | \brief A window overlay for popups. |
59 | |
60 | Overlay provides a layer for popups, ensuring that popups are displayed above |
61 | other content and that the background is dimmed when a \l {Popup::}{modal} or |
62 | \l {Popup::dim}{dimmed} popup is visible. |
63 | |
64 | The overlay is an ordinary Item that covers the entire window. It can be used |
65 | as a visual parent to position a popup in scene coordinates. |
66 | |
67 | \include qquickoverlay-popup-parent.qdocinc |
68 | |
69 | \sa ApplicationWindow |
70 | */ |
71 | |
72 | QVector<QQuickPopup *> QQuickOverlayPrivate::() const |
73 | { |
74 | const QList<QQuickItem *> children = paintOrderChildItems(); |
75 | |
76 | QVector<QQuickPopup *> ; |
77 | popups.reserve(asize: children.count()); |
78 | |
79 | for (auto it = children.crbegin(), end = children.crend(); it != end; ++it) { |
80 | QQuickPopup * = qobject_cast<QQuickPopup *>(object: (*it)->parent()); |
81 | if (popup) |
82 | popups += popup; |
83 | } |
84 | |
85 | return popups; |
86 | } |
87 | |
88 | QVector<QQuickDrawer *> QQuickOverlayPrivate::stackingOrderDrawers() const |
89 | { |
90 | QVector<QQuickDrawer *> sorted(allDrawers); |
91 | std::sort(first: sorted.begin(), last: sorted.end(), comp: [](const QQuickDrawer *one, const QQuickDrawer *another) { |
92 | return one->z() > another->z(); |
93 | }); |
94 | return sorted; |
95 | } |
96 | |
97 | void QQuickOverlayPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) |
98 | { |
99 | updateGeometry(); |
100 | } |
101 | |
102 | bool QQuickOverlayPrivate::startDrag(QEvent *event, const QPointF &pos) |
103 | { |
104 | Q_Q(QQuickOverlay); |
105 | if (allDrawers.isEmpty()) |
106 | return false; |
107 | |
108 | // don't start dragging a drawer if a modal popup overlay is blocking (QTBUG-60602) |
109 | QQuickItem *item = q->childAt(x: pos.x(), y: pos.y()); |
110 | if (item) { |
111 | const auto = stackingOrderPopups(); |
112 | for (QQuickPopup * : popups) { |
113 | QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); |
114 | if (p->dimmer == item && popup->isVisible() && popup->isModal()) |
115 | return false; |
116 | } |
117 | } |
118 | |
119 | const QVector<QQuickDrawer *> drawers = stackingOrderDrawers(); |
120 | for (QQuickDrawer *drawer : drawers) { |
121 | QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer); |
122 | if (p->startDrag(event)) { |
123 | setMouseGrabberPopup(drawer); |
124 | return true; |
125 | } |
126 | } |
127 | |
128 | return false; |
129 | } |
130 | |
131 | bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target) |
132 | { |
133 | if (target) { |
134 | if (target->overlayEvent(item: source, event)) { |
135 | setMouseGrabberPopup(target); |
136 | return true; |
137 | } |
138 | return false; |
139 | } |
140 | |
141 | switch (event->type()) { |
142 | default: { |
143 | if (mouseGrabberPopup) |
144 | break; |
145 | #if QT_CONFIG(quicktemplates2_multitouch) |
146 | Q_FALLTHROUGH(); |
147 | case QEvent::TouchBegin: |
148 | case QEvent::TouchUpdate: |
149 | case QEvent::TouchEnd: |
150 | #endif |
151 | // allow non-modal popups to close themselves, |
152 | // and non-dimming modal popups to block the event |
153 | const auto = stackingOrderPopups(); |
154 | for (QQuickPopup * : popups) { |
155 | if (popup->overlayEvent(item: source, event)) { |
156 | setMouseGrabberPopup(popup); |
157 | return true; |
158 | } |
159 | } |
160 | break; |
161 | } |
162 | } |
163 | |
164 | event->ignore(); |
165 | return false; |
166 | } |
167 | |
168 | bool QQuickOverlayPrivate::handleMove(QQuickItem *source, QEvent *event, QQuickPopup *target) |
169 | { |
170 | if (target) |
171 | return target->overlayEvent(item: source, event); |
172 | return false; |
173 | } |
174 | |
175 | bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target) |
176 | { |
177 | if (target) { |
178 | setMouseGrabberPopup(nullptr); |
179 | if (target->overlayEvent(item: source, event)) { |
180 | setMouseGrabberPopup(nullptr); |
181 | return true; |
182 | } |
183 | } else { |
184 | const auto = stackingOrderPopups(); |
185 | for (QQuickPopup * : popups) { |
186 | if (popup->overlayEvent(item: source, event)) |
187 | return true; |
188 | } |
189 | } |
190 | return false; |
191 | } |
192 | |
193 | bool QQuickOverlayPrivate::handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target) |
194 | { |
195 | switch (event->type()) { |
196 | case QEvent::MouseButtonPress: |
197 | if (!target && startDrag(event, pos: event->windowPos())) |
198 | return true; |
199 | return handlePress(source, event, target); |
200 | case QEvent::MouseMove: |
201 | return handleMove(source, event, target: target ? target : mouseGrabberPopup.data()); |
202 | case QEvent::MouseButtonRelease: |
203 | return handleRelease(source, event, target: target ? target : mouseGrabberPopup.data()); |
204 | default: |
205 | break; |
206 | } |
207 | return false; |
208 | } |
209 | |
210 | #if QT_CONFIG(quicktemplates2_multitouch) |
211 | bool QQuickOverlayPrivate::handleTouchEvent(QQuickItem *source, QTouchEvent *event, QQuickPopup *target) |
212 | { |
213 | bool handled = false; |
214 | switch (event->type()) { |
215 | case QEvent::TouchBegin: |
216 | case QEvent::TouchUpdate: |
217 | case QEvent::TouchEnd: |
218 | for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { |
219 | switch (point.state()) { |
220 | case Qt::TouchPointPressed: |
221 | if (!target && startDrag(event, pos: point.scenePos())) |
222 | handled = true; |
223 | else |
224 | handled |= handlePress(source, event, target); |
225 | break; |
226 | case Qt::TouchPointMoved: |
227 | handled |= handleMove(source, event, target: target ? target : mouseGrabberPopup.data()); |
228 | break; |
229 | case Qt::TouchPointReleased: |
230 | handled |= handleRelease(source, event, target: target ? target : mouseGrabberPopup.data()); |
231 | break; |
232 | default: |
233 | break; |
234 | } |
235 | } |
236 | break; |
237 | |
238 | default: |
239 | break; |
240 | } |
241 | |
242 | return handled; |
243 | } |
244 | #endif |
245 | |
246 | void QQuickOverlayPrivate::(QQuickPopup *) |
247 | { |
248 | Q_Q(QQuickOverlay); |
249 | allPopups += popup; |
250 | if (QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(object: popup)) { |
251 | allDrawers += drawer; |
252 | q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty()); |
253 | } |
254 | } |
255 | |
256 | void QQuickOverlayPrivate::(QQuickPopup *) |
257 | { |
258 | Q_Q(QQuickOverlay); |
259 | allPopups.removeOne(t: popup); |
260 | if (allDrawers.removeOne(t: qobject_cast<QQuickDrawer *>(object: popup))) |
261 | q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty()); |
262 | } |
263 | |
264 | void QQuickOverlayPrivate::(QQuickPopup *) |
265 | { |
266 | if (popup && !popup->isVisible()) |
267 | popup = nullptr; |
268 | mouseGrabberPopup = popup; |
269 | } |
270 | |
271 | void QQuickOverlayPrivate::updateGeometry() |
272 | { |
273 | Q_Q(QQuickOverlay); |
274 | if (!window) |
275 | return; |
276 | |
277 | QPointF pos; |
278 | QSizeF size = window->size(); |
279 | qreal rotation = 0; |
280 | |
281 | switch (window->contentOrientation()) { |
282 | case Qt::PrimaryOrientation: |
283 | case Qt::PortraitOrientation: |
284 | size = window->size(); |
285 | break; |
286 | case Qt::LandscapeOrientation: |
287 | rotation = 90; |
288 | pos = QPointF((size.width() - size.height()) / 2, -(size.width() - size.height()) / 2); |
289 | size.transpose(); |
290 | break; |
291 | case Qt::InvertedPortraitOrientation: |
292 | rotation = 180; |
293 | break; |
294 | case Qt::InvertedLandscapeOrientation: |
295 | rotation = 270; |
296 | pos = QPointF((size.width() - size.height()) / 2, -(size.width() - size.height()) / 2); |
297 | size.transpose(); |
298 | break; |
299 | default: |
300 | break; |
301 | } |
302 | |
303 | q->setSize(size); |
304 | q->setPosition(pos); |
305 | q->setRotation(rotation); |
306 | } |
307 | |
308 | QQuickOverlay::QQuickOverlay(QQuickItem *parent) |
309 | : QQuickItem(*(new QQuickOverlayPrivate), parent) |
310 | { |
311 | Q_D(QQuickOverlay); |
312 | setZ(1000001); // DefaultWindowDecoration+1 |
313 | setAcceptedMouseButtons(Qt::AllButtons); |
314 | #if QT_CONFIG(quicktemplates2_multitouch) |
315 | setAcceptTouchEvents(true); |
316 | #endif |
317 | setFiltersChildMouseEvents(true); |
318 | setVisible(false); |
319 | |
320 | if (parent) { |
321 | d->updateGeometry(); |
322 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener: d, types: QQuickItemPrivate::Geometry); |
323 | if (QQuickWindow *window = parent->window()) { |
324 | window->installEventFilter(filterObj: this); |
325 | QObjectPrivate::connect(sender: window, signal: &QWindow::contentOrientationChanged, receiverPrivate: d, slot: &QQuickOverlayPrivate::updateGeometry); |
326 | } |
327 | } |
328 | } |
329 | |
330 | QQuickOverlay::~QQuickOverlay() |
331 | { |
332 | Q_D(QQuickOverlay); |
333 | if (QQuickItem *parent = parentItem()) |
334 | QQuickItemPrivate::get(item: parent)->removeItemChangeListener(d, types: QQuickItemPrivate::Geometry); |
335 | } |
336 | |
337 | QQmlComponent *QQuickOverlay::modal() const |
338 | { |
339 | Q_D(const QQuickOverlay); |
340 | return d->modal; |
341 | } |
342 | |
343 | void QQuickOverlay::setModal(QQmlComponent *modal) |
344 | { |
345 | Q_D(QQuickOverlay); |
346 | if (d->modal == modal) |
347 | return; |
348 | |
349 | d->modal = modal; |
350 | emit modalChanged(); |
351 | } |
352 | |
353 | QQmlComponent *QQuickOverlay::modeless() const |
354 | { |
355 | Q_D(const QQuickOverlay); |
356 | return d->modeless; |
357 | } |
358 | |
359 | void QQuickOverlay::setModeless(QQmlComponent *modeless) |
360 | { |
361 | Q_D(QQuickOverlay); |
362 | if (d->modeless == modeless) |
363 | return; |
364 | |
365 | d->modeless = modeless; |
366 | emit modelessChanged(); |
367 | } |
368 | |
369 | QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window) |
370 | { |
371 | if (!window) |
372 | return nullptr; |
373 | |
374 | QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow *>(object: window); |
375 | if (applicationWindow) |
376 | return applicationWindow->overlay(); |
377 | |
378 | const char *name = "_q_QQuickOverlay" ; |
379 | QQuickOverlay *overlay = window->property(name).value<QQuickOverlay *>(); |
380 | if (!overlay) { |
381 | QQuickItem *content = window->contentItem(); |
382 | // Do not re-create the overlay if the window is being destroyed |
383 | // and thus, its content item no longer has a window associated. |
384 | if (content && content->window()) { |
385 | overlay = new QQuickOverlay(window->contentItem()); |
386 | window->setProperty(name, value: QVariant::fromValue(value: overlay)); |
387 | } |
388 | } |
389 | return overlay; |
390 | } |
391 | |
392 | QQuickOverlayAttached *QQuickOverlay::qmlAttachedProperties(QObject *object) |
393 | { |
394 | return new QQuickOverlayAttached(object); |
395 | } |
396 | |
397 | void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) |
398 | { |
399 | Q_D(QQuickOverlay); |
400 | QQuickItem::itemChange(change, data); |
401 | |
402 | if (change == ItemChildAddedChange || change == ItemChildRemovedChange) |
403 | setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty()); |
404 | } |
405 | |
406 | void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) |
407 | { |
408 | Q_D(QQuickOverlay); |
409 | QQuickItem::geometryChanged(newGeometry, oldGeometry); |
410 | for (QQuickPopup * : qAsConst(t&: d->allPopups)) |
411 | QQuickPopupPrivate::get(popup)->resizeOverlay(); |
412 | } |
413 | |
414 | void QQuickOverlay::mousePressEvent(QMouseEvent *event) |
415 | { |
416 | Q_D(QQuickOverlay); |
417 | d->handleMouseEvent(source: this, event); |
418 | } |
419 | |
420 | void QQuickOverlay::mouseMoveEvent(QMouseEvent *event) |
421 | { |
422 | Q_D(QQuickOverlay); |
423 | d->handleMouseEvent(source: this, event); |
424 | } |
425 | |
426 | void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event) |
427 | { |
428 | Q_D(QQuickOverlay); |
429 | d->handleMouseEvent(source: this, event); |
430 | } |
431 | |
432 | #if QT_CONFIG(quicktemplates2_multitouch) |
433 | void QQuickOverlay::touchEvent(QTouchEvent *event) |
434 | { |
435 | Q_D(QQuickOverlay); |
436 | d->handleTouchEvent(source: this, event); |
437 | } |
438 | #endif |
439 | |
440 | #if QT_CONFIG(wheelevent) |
441 | void QQuickOverlay::wheelEvent(QWheelEvent *event) |
442 | { |
443 | Q_D(QQuickOverlay); |
444 | if (d->mouseGrabberPopup) { |
445 | d->mouseGrabberPopup->overlayEvent(item: this, event); |
446 | return; |
447 | } else { |
448 | const auto = d->stackingOrderPopups(); |
449 | for (QQuickPopup * : popups) { |
450 | if (popup->overlayEvent(item: this, event)) |
451 | return; |
452 | } |
453 | } |
454 | event->ignore(); |
455 | } |
456 | #endif |
457 | |
458 | bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) |
459 | { |
460 | Q_D(QQuickOverlay); |
461 | const auto = d->stackingOrderPopups(); |
462 | for (QQuickPopup * : popups) { |
463 | QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); |
464 | |
465 | // Stop filtering overlay events when reaching a popup item or an item |
466 | // that is inside the popup. Let the popup content handle its events. |
467 | if (item == p->popupItem || p->popupItem->isAncestorOf(child: item)) |
468 | break; |
469 | |
470 | // Let the popup try closing itself when pressing or releasing over its |
471 | // background dimming OR over another popup underneath, in case the popup |
472 | // does not have background dimming. |
473 | if (item == p->dimmer || !p->popupItem->isAncestorOf(child: item)) { |
474 | bool handled = false; |
475 | switch (event->type()) { |
476 | #if QT_CONFIG(quicktemplates2_multitouch) |
477 | case QEvent::TouchBegin: |
478 | case QEvent::TouchUpdate: |
479 | case QEvent::TouchEnd: |
480 | handled = d->handleTouchEvent(source: item, event: static_cast<QTouchEvent *>(event), target: popup); |
481 | break; |
482 | #endif |
483 | |
484 | case QEvent::MouseButtonPress: |
485 | case QEvent::MouseMove: |
486 | case QEvent::MouseButtonRelease: |
487 | handled = d->handleMouseEvent(source: item, event: static_cast<QMouseEvent *>(event), target: popup); |
488 | break; |
489 | |
490 | default: |
491 | break; |
492 | } |
493 | if (handled) |
494 | return true; |
495 | } |
496 | } |
497 | return false; |
498 | } |
499 | |
500 | bool QQuickOverlay::eventFilter(QObject *object, QEvent *event) |
501 | { |
502 | Q_D(QQuickOverlay); |
503 | if (!isVisible() || object != d->window) |
504 | return false; |
505 | |
506 | switch (event->type()) { |
507 | #if QT_CONFIG(quicktemplates2_multitouch) |
508 | case QEvent::TouchBegin: |
509 | case QEvent::TouchUpdate: |
510 | case QEvent::TouchEnd: |
511 | if (static_cast<QTouchEvent *>(event)->touchPointStates() & Qt::TouchPointPressed) |
512 | emit pressed(); |
513 | if (static_cast<QTouchEvent *>(event)->touchPointStates() & Qt::TouchPointReleased) |
514 | emit released(); |
515 | |
516 | // allow non-modal popups to close on touch release outside |
517 | if (!d->mouseGrabberPopup) { |
518 | for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->touchPoints()) { |
519 | if (point.state() == Qt::TouchPointReleased) { |
520 | if (d->handleRelease(source: d->window->contentItem(), event, target: nullptr)) |
521 | break; |
522 | } |
523 | } |
524 | } |
525 | |
526 | QQuickWindowPrivate::get(c: d->window)->handleTouchEvent(static_cast<QTouchEvent *>(event)); |
527 | |
528 | // If a touch event hasn't been accepted after being delivered, there |
529 | // were no items interested in touch events at any of the touch points. |
530 | // Make sure to accept the touch event in order to receive the consequent |
531 | // touch events, to be able to close non-modal popups on release outside. |
532 | event->accept(); |
533 | return true; |
534 | #endif |
535 | |
536 | case QEvent::MouseButtonPress: |
537 | #if QT_CONFIG(quicktemplates2_multitouch) |
538 | // do not emit pressed() twice when mouse events have been synthesized from touch events |
539 | if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) |
540 | #endif |
541 | emit pressed(); |
542 | |
543 | QQuickWindowPrivate::get(c: d->window)->handleMouseEvent(static_cast<QMouseEvent *>(event)); |
544 | |
545 | // If a mouse event hasn't been accepted after being delivered, there |
546 | // was no item interested in mouse events at the mouse point. Make sure |
547 | // to accept the mouse event in order to receive the consequent mouse |
548 | // events, to be able to close non-modal popups on release outside. |
549 | event->accept(); |
550 | return true; |
551 | |
552 | case QEvent::MouseButtonRelease: |
553 | #if QT_CONFIG(quicktemplates2_multitouch) |
554 | // do not emit released() twice when mouse events have been synthesized from touch events |
555 | if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) |
556 | #endif |
557 | emit released(); |
558 | |
559 | // allow non-modal popups to close on mouse release outside |
560 | if (!d->mouseGrabberPopup) |
561 | d->handleRelease(source: d->window->contentItem(), event, target: nullptr); |
562 | break; |
563 | |
564 | default: |
565 | break; |
566 | } |
567 | |
568 | return false; |
569 | } |
570 | |
571 | class QQuickOverlayAttachedPrivate : public QObjectPrivate |
572 | { |
573 | Q_DECLARE_PUBLIC(QQuickOverlayAttached) |
574 | |
575 | public: |
576 | void setWindow(QQuickWindow *newWindow); |
577 | |
578 | QQuickWindow *window = nullptr; |
579 | QQmlComponent *modal = nullptr; |
580 | QQmlComponent *modeless = nullptr; |
581 | }; |
582 | |
583 | void QQuickOverlayAttachedPrivate::setWindow(QQuickWindow *newWindow) |
584 | { |
585 | Q_Q(QQuickOverlayAttached); |
586 | if (window == newWindow) |
587 | return; |
588 | |
589 | if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window)) { |
590 | QObject::disconnect(sender: oldOverlay, signal: &QQuickOverlay::pressed, receiver: q, slot: &QQuickOverlayAttached::pressed); |
591 | QObject::disconnect(sender: oldOverlay, signal: &QQuickOverlay::released, receiver: q, slot: &QQuickOverlayAttached::released); |
592 | } |
593 | |
594 | if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(window: newWindow)) { |
595 | QObject::connect(sender: newOverlay, signal: &QQuickOverlay::pressed, receiver: q, slot: &QQuickOverlayAttached::pressed); |
596 | QObject::connect(sender: newOverlay, signal: &QQuickOverlay::released, receiver: q, slot: &QQuickOverlayAttached::released); |
597 | } |
598 | |
599 | window = newWindow; |
600 | emit q->overlayChanged(); |
601 | } |
602 | |
603 | /*! |
604 | \qmlattachedsignal QtQuick.Controls::Overlay::pressed() |
605 | |
606 | This attached signal is emitted when the overlay is pressed by the user while |
607 | a popup is visible. |
608 | |
609 | The signal can be attached to any item, popup, or window. When attached to an |
610 | item or a popup, the signal is only emitted if the item or popup is in a window. |
611 | */ |
612 | |
613 | /*! |
614 | \qmlattachedsignal QtQuick.Controls::Overlay::released() |
615 | |
616 | This attached signal is emitted when the overlay is released by the user while |
617 | a popup is visible. |
618 | |
619 | The signal can be attached to any item, popup, or window. When attached to an |
620 | item or a popup, the signal is only emitted if the item or popup is in a window. |
621 | */ |
622 | |
623 | QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent) |
624 | : QObject(*(new QQuickOverlayAttachedPrivate), parent) |
625 | { |
626 | Q_D(QQuickOverlayAttached); |
627 | if (QQuickItem *item = qobject_cast<QQuickItem *>(object: parent)) { |
628 | d->setWindow(item->window()); |
629 | QObjectPrivate::connect(sender: item, signal: &QQuickItem::windowChanged, receiverPrivate: d, slot: &QQuickOverlayAttachedPrivate::setWindow); |
630 | } else if (QQuickPopup * = qobject_cast<QQuickPopup *>(object: parent)) { |
631 | d->setWindow(popup->window()); |
632 | QObjectPrivate::connect(sender: popup, signal: &QQuickPopup::windowChanged, receiverPrivate: d, slot: &QQuickOverlayAttachedPrivate::setWindow); |
633 | } else { |
634 | d->setWindow(qobject_cast<QQuickWindow *>(object: parent)); |
635 | } |
636 | } |
637 | |
638 | /*! |
639 | \qmlattachedproperty Overlay QtQuick.Controls::Overlay::overlay |
640 | \readonly |
641 | |
642 | This attached property holds the window overlay item. |
643 | |
644 | The property can be attached to any item, popup, or window. When attached to an |
645 | item or a popup, the value is \c null if the item or popup is not in a window. |
646 | */ |
647 | QQuickOverlay *QQuickOverlayAttached::overlay() const |
648 | { |
649 | Q_D(const QQuickOverlayAttached); |
650 | return QQuickOverlay::overlay(window: d->window); |
651 | } |
652 | |
653 | /*! |
654 | \qmlattachedproperty Component QtQuick.Controls::Overlay::modal |
655 | |
656 | This attached property holds a component to use as a visual item that implements |
657 | background dimming for modal popups. It is created for and stacked below visible |
658 | modal popups. |
659 | |
660 | The property can be attached to any popup. |
661 | |
662 | For example, to change the color of the background dimming for a modal |
663 | popup, the following code can be used: |
664 | |
665 | \snippet qtquickcontrols2-overlay-modal.qml 1 |
666 | |
667 | \sa Popup::modal |
668 | */ |
669 | QQmlComponent *QQuickOverlayAttached::modal() const |
670 | { |
671 | Q_D(const QQuickOverlayAttached); |
672 | return d->modal; |
673 | } |
674 | |
675 | void QQuickOverlayAttached::setModal(QQmlComponent *modal) |
676 | { |
677 | Q_D(QQuickOverlayAttached); |
678 | if (d->modal == modal) |
679 | return; |
680 | |
681 | d->modal = modal; |
682 | emit modalChanged(); |
683 | } |
684 | |
685 | /*! |
686 | \qmlattachedproperty Component QtQuick.Controls::Overlay::modeless |
687 | |
688 | This attached property holds a component to use as a visual item that implements |
689 | background dimming for modeless popups. It is created for and stacked below visible |
690 | dimming popups. |
691 | |
692 | The property can be attached to any popup. |
693 | |
694 | For example, to change the color of the background dimming for a modeless |
695 | popup, the following code can be used: |
696 | |
697 | \snippet qtquickcontrols2-overlay-modeless.qml 1 |
698 | |
699 | \sa Popup::dim |
700 | */ |
701 | QQmlComponent *QQuickOverlayAttached::modeless() const |
702 | { |
703 | Q_D(const QQuickOverlayAttached); |
704 | return d->modeless; |
705 | } |
706 | |
707 | void QQuickOverlayAttached::setModeless(QQmlComponent *modeless) |
708 | { |
709 | Q_D(QQuickOverlayAttached); |
710 | if (d->modeless == modeless) |
711 | return; |
712 | |
713 | d->modeless = modeless; |
714 | emit modelessChanged(); |
715 | } |
716 | |
717 | QT_END_NAMESPACE |
718 | |