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
qquickpopup.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
14#if QT_CONFIG(quicktemplates2_container)
15#include "qquickdialog_p.h"
16#endif
17
18#include <QtCore/qloggingcategory.h>
19#include <QtQml/qqmlinfo.h>
20#include <QtQuick/qquickitem.h>
21#include <QtQuick/private/qquickaccessibleattached_p.h>
22#include <QtQuick/private/qquickattachedpropertypropagator_p.h>
23#include <QtQuick/private/qquicktransition_p.h>
24#include <QtQuick/private/qquickitem_p.h>
25#include <qpa/qplatformintegration.h>
26#include <private/qguiapplication_p.h>
27
29
30Q_STATIC_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer")
31Q_STATIC_LOGGING_CATEGORY(lcQuickPopup, "qt.quick.controls.popup")
32
33/*!
34 \qmltype Popup
35 \inherits QtObject
36//! \nativetype QQuickPopup
37 \inqmlmodule QtQuick.Controls
38 \since 5.7
39 \ingroup qtquickcontrols-popups
40 \ingroup qtquickcontrols-focusscopes
41 \brief Base type of popup-like user interface controls.
42
43 Popup is the base type of popup-like user interface controls. It can be
44 used with \l Window or \l ApplicationWindow.
45
46 \qml
47 import QtQuick.Window
48 import QtQuick.Controls
49
50 ApplicationWindow {
51 id: window
52 width: 400
53 height: 400
54 visible: true
55
56 Button {
57 text: "Open"
58 onClicked: popup.open()
59 }
60
61 Popup {
62 id: popup
63 x: 100
64 y: 100
65 width: 200
66 height: 300
67 modal: true
68 focus: true
69 closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
70 }
71 }
72 \endqml
73
74 Popup does not provide a layout of its own, but requires you to position
75 its contents, for instance by creating a \l RowLayout or a \l ColumnLayout.
76
77 Items declared as children of a Popup are automatically parented to the
78 Popups's \l contentItem. Items created dynamically need to be explicitly
79 parented to the contentItem.
80
81 \section1 Popup Layout
82
83 The following diagram illustrates the layout of a popup within a window:
84
85 \image qtquickcontrols-popup.png
86 {Popup window overlaying content}
87
88 The \l implicitWidth and \l implicitHeight of a popup are typically based
89 on the implicit sizes of the background and the content item plus any insets
90 and paddings. These properties determine how large the popup will be when no
91 explicit \l width or \l height is specified.
92
93 The geometry of the \l contentItem is determined by the padding. The following
94 example reserves 10px padding between the boundaries of the popup and its content:
95
96 \code
97 Popup {
98 padding: 10
99
100 contentItem: Text {
101 text: "Content"
102 }
103 }
104 \endcode
105
106 The \l background item fills the entire width and height of the popup,
107 unless insets or an explicit size have been given for it.
108
109 Negative insets can be used to make the background larger than the popup.
110 The following example uses negative insets to place a shadow outside the
111 popup's boundaries:
112
113 \code
114 Popup {
115 topInset: -2
116 leftInset: -2
117 rightInset: -6
118 bottomInset: -6
119
120 background: BorderImage {
121 source: ":/images/shadowed-background.png"
122 }
123 }
124 \endcode
125
126 \section1 Popup type
127
128 Since Qt 6.8, some popups, such as \l Menu, offer three different implementations,
129 depending on the platform. You can choose which one you prefer by setting \l popupType.
130
131 Whether a popup will be able to use the preferred type depends on the platform.
132 \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
133 are normally only supported on desktop platforms. Additionally, if a popup is a
134 \l Menu inside a \l {Native menu bars}{native menubar}, the menu will be native as
135 well. And if the menu is a sub-menu inside another menu, the parent (or root) menu
136 will decide the type.
137
138 \section2 Showing a popup as an item
139
140 By setting \l popupType to \c Popup.Item, the popup will \e not be shown as a separate
141 window, but as an item inside the same scene as the parent. This item is parented
142 to that scene's \l{Overlay::overlay}{overlay}, and styled to look like an actual window.
143
144 This option is especially useful on platforms that doesn't support multiple windows.
145 This was also the only option before Qt 6.8.
146
147 In order to ensure that a popup is displayed above other items in the
148 scene, it is recommended to use ApplicationWindow. ApplicationWindow also
149 provides background dimming effects.
150
151 \section2 Showing a popup as a separate window
152
153 By setting \l popupType to \c Popup.Window, the popup will be shown inside a top-level
154 \l {QQuickWindow}{window} configured with the \l Qt::Popup flag. Using a window to show a
155 popup has the advantage that the popup will float on top of the parent window, and
156 can be placed outside of its geometry. The popup will otherwise look the same as when
157 using \c Popup.Item, that is, it will use the same QML delegates and styling as
158 when using \c Popup.Item.
159
160 \note If the platform doesn't support \c Popup.Window, \c Popup.Item will be used as fallback.
161
162 \section2 Showing a native popup
163
164 By setting \l popupType to \c Popup.Native, the popup will be shown using a platform
165 native popup window. This window, and all its contents, will be rendered by the
166 platform, and not by QML. This means that the QML delegates assigned to the popup
167 will \e not be used for rendering. If you for example
168 use this option on a \l Menu, it will be implemented using platform-specific
169 menu APIs. This will normally make the popup look and feel more native than for example
170 \c Popup.Window, but at the same time, suffer from platform limitations and differences
171 related to appearance and behavior. Such limitations are documented in more detail
172 in the subclasses that are affected, such as for a
173 \l {Limitations when using native menus}{Menu}).
174
175 \note If the platform doesn't support \c Popup.Native, \c Popup.Window will be used as fallback.
176
177 \section1 Popup Sizing
178
179 If only a single item is used within a Popup, it will resize to fit the
180 implicit size of its contained item. This makes it particularly suitable
181 for use together with layouts.
182
183 \code
184 Popup {
185 ColumnLayout {
186 anchors.fill: parent
187 CheckBox { text: qsTr("E-mail") }
188 CheckBox { text: qsTr("Calendar") }
189 CheckBox { text: qsTr("Contacts") }
190 }
191 }
192 \endcode
193
194 Sometimes there might be two items within the popup:
195
196 \code
197 Popup {
198 SwipeView {
199 // ...
200 }
201 PageIndicator {
202 anchors.horizontalCenter: parent.horizontalCenter
203 anchors.bottom: parent.bottom
204 }
205 }
206 \endcode
207
208 In this case, Popup cannot calculate a sensible implicit size. Since we're
209 anchoring the \l PageIndicator over the \l SwipeView, we can simply set the
210 content size to the view's implicit size:
211
212 \code
213 Popup {
214 contentWidth: view.implicitWidth
215 contentHeight: view.implicitHeight
216
217 SwipeView {
218 id: view
219 // ...
220 }
221 PageIndicator {
222 anchors.horizontalCenter: parent.horizontalCenter
223 anchors.bottom: parent.bottom
224 }
225 }
226 \endcode
227
228 \note When using \l {Showing a popup as an item}{popup items}, the popup's
229 \l{contentItem}{content item} gets parented to the \l{Overlay::}{overlay},
230 and does not live within the popup's parent. Because of that, a \l{Item::}
231 {scale} applied to the tree in which the popup lives does not apply to the
232 visual popup. To make the popup of e.g. a \l{ComboBox} follow the scale of
233 the combobox, apply the same scale to the \l{Overlay::}{overlay} as well:
234
235 \code
236 Window {
237 property double scaleFactor: 2.0
238
239 Scale {
240 id: scale
241 xScale: scaleFactor
242 yScale: scaleFactor
243 }
244 Item {
245 id: scaledContent
246 transform: scale
247
248 ComboBox {
249 id: combobox
250 // ...
251 }
252 }
253
254 Overlay.overlay.transform: scale
255 }
256 \endcode
257
258 \section1 Popup Positioning
259
260 Similar to items in Qt Quick, Popup's \l x and \l y coordinates are
261 relative to its parent. This means that opening a popup that is a
262 child of a \l Button, for example, will cause the popup to be positioned
263 relative to the button.
264
265 \include qquickoverlay-popup-parent.qdocinc
266
267 Another way to center a popup in the window regardless of its parent item
268 is to use \l {anchors.centerIn}:
269
270 \snippet qtquickcontrols-popup.qml centerIn
271
272 To ensure that the popup is positioned within the bounds of the enclosing
273 window, the \l margins property can be set to a non-negative value.
274
275 \section1 Using the overlay
276
277 In cases where \l {Showing a popup as an item}{popup windows} are not being used,
278 Popup sets its contentItem's \l{qtquick-visualcanvas-visualparent.html}{visual parent}
279 to be the window's \l {Overlay::overlay}{overlay}, in order to ensure that
280 the popup appears in front of everything else in the scene. Its main task is to
281 intercept events to prevent delivery to items under a \l modal popup, and to close
282 the popup according to its \l closePolicy.
283
284 In some cases, it might be useful to put an item in front of a popup,
285 such as a \l [QML QtVirtualKeyboard] {InputPanel} {virtual keyboard}.
286 This can currently only be done by setting the item's parent to the overlay,
287 and ensuring that the item is stacked before any popup item, which a positive
288 \l z value ensures.
289
290 It's generally not recommended to use the overlay in this way, since the overlay wasn't
291 designed for this purpose, and the behavior won't be consistent when changing the \l popupType.
292
293 \omit
294 This shouldn't be a snippet, since we don't want VKB to be a dependency to controls.
295 \endomit
296 \qml
297 Popup {
298 id: popup
299 visible: true
300 anchors.centerIn: parent
301 margins: 10
302 closePolicy: Popup.CloseOnEscape
303 ColumnLayout {
304 TextField {
305 placeholderText: qsTr("Username")
306 }
307 TextField {
308 placeholderText: qsTr("Password")
309 echoMode: TextInput.Password
310 }
311 }
312 }
313 InputPanel {
314 parent: Overlay.overlay
315 width: parent.width
316 y: popup.y + popup.topMargin + (window.activeFocusItem?.y ?? 0) + (window.activeFocusItem?.height ?? 0)
317 z: 1
318 }
319 \endqml
320
321 \section1 Popup Transitions
322
323 After the exit transition is finished, these properties will be reset to
324 their values before the enter transition is started.
325
326 \list
327 \li \l opacity
328 \li \l scale
329 \endlist
330
331 This allows the built-in styles to animate on these properties without losing any explicitly
332 defined value.
333
334 \section1 Back/Escape Event Handling
335
336 By default, a Popup will close if:
337 \list
338 \li It has \l activeFocus,
339 \li Its \l closePolicy is \c {Popup.CloseOnEscape}, and
340 \li The user presses the key sequence for QKeySequence::Cancel (typically
341 the Escape key)
342 \endlist
343
344 To prevent this from happening, either:
345
346 \list
347 \li Don't give the popup \l focus.
348 \li Set the popup's \l closePolicy to a value that does not include
349 \c {Popup.CloseOnEscape}.
350 \li Handle \l {Keys}' \l {Keys::}{escapePressed} signal in a child item of
351 the popup so that it gets the event before the Popup.
352 \endlist
353
354 \sa {Popup Controls}, {Customizing Popup}, ApplicationWindow
355
356 \section1 Property Propagation
357
358 Popup inherits fonts, palettes and attached properties through its parent
359 window, not its
360 \l {Concepts - Visual Parent in Qt Quick#Visual Parent}{object or visual parent}:
361
362 \snippet qtquickcontrols-popup-property-propagation.qml file
363
364 \image qtquickcontrols-basic-popup-property-propagation.png
365 {Diagram showing popup property inheritance}
366
367 In addition, popups do not propagate their properties to child popups. This
368 behavior is modelled on Qt Widgets, where a \c Qt::Popup widget is a
369 top-level window. Top-level windows do not propagate their properties to
370 child windows.
371
372 Certain derived types like ComboBox are typically implemented in such a way
373 that the popup is considered an integral part of the control, and as such,
374 may inherit things like attached properties. For example, in the
375 \l {Material Style}{Material style} ComboBox, the theme and other attached
376 properties are explicitly inherited by the Popup from the ComboBox itself:
377
378 \code
379 popup: T.Popup {
380 // ...
381
382 Material.theme: control.Material.theme
383 Material.accent: control.Material.accent
384 Material.primary: control.Material.primary
385 }
386 \endcode
387
388 So, to ensure that a child popup has the same property values as its parent
389 popup, explicitly set those properties:
390
391 \code
392 Popup {
393 id: parentPopup
394 // ...
395
396 Popup {
397 palette: parentPopup.palette
398 }
399 }
400 \endcode
401
402 \section1 Polish Behavior of Closed Popups
403
404 When a popup is closed, it has no associated window, and neither do its
405 child items. This means that any child items will not be
406 \l {QQuickItem::polish}{polished} until the popup is shown. For this
407 reason, you cannot, for example, rely on a \l ListView within a closed
408 \c Popup to update its \c count property:
409
410 \code
411 import QtQuick
412 import QtQuick.Controls
413
414 ApplicationWindow {
415 width: 640
416 height: 480
417 visible: true
418
419 SomeModel {
420 id: someModel
421 }
422
423 Button {
424 text: view.count
425 onClicked: popup.open()
426 }
427
428 Popup {
429 id: popup
430 width: 400
431 height: 400
432 contentItem: ListView {
433 id: view
434 model: someModel
435 delegate: Label {
436 text: display
437
438 required property string display
439 }
440 }
441 }
442 }
443 \endcode
444
445 In the example above, the Button's text will not update when rows are added
446 to or removed from \c someModel after \l {Component::completed}{component
447 completion} while the popup is closed.
448
449 Instead, a \c count property can be added to \c SomeModel that is updated
450 whenever the \l {QAbstractItemModel::}{rowsInserted}, \l
451 {QAbstractItemModel::}{rowsRemoved}, and \l
452 {QAbstractItemModel::}{modelReset} signals are emitted. The \c Button can
453 then bind this property to its \c text.
454*/
455
456/*!
457 \qmlsignal void QtQuick.Controls::Popup::opened()
458
459 This signal is emitted when the popup is opened.
460
461 \sa aboutToShow()
462*/
463
464/*!
465 \qmlsignal void QtQuick.Controls::Popup::closed()
466
467 This signal is emitted when the popup is closed.
468
469 \sa aboutToHide()
470*/
471
472/*!
473 \qmlsignal void QtQuick.Controls::Popup::aboutToShow()
474
475 This signal is emitted when the popup is about to show.
476
477 \sa opened()
478*/
479
480/*!
481 \qmlsignal void QtQuick.Controls::Popup::aboutToHide()
482
483 This signal is emitted when the popup is about to hide.
484
485 \sa closed()
486*/
487
488QQuickItem *QQuickPopup::findParentItem() const
489{
490 QObject *obj = parent();
491 while (obj) {
492 QQuickItem *item = qobject_cast<QQuickItem *>(obj);
493 if (item)
494 return item;
495 obj = obj->parent();
496 }
497 return nullptr;
498}
499
500const QQuickPopup::ClosePolicy QQuickPopupPrivate::DefaultClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside;
501
502QQuickPopupPrivate::QQuickPopupPrivate()
503 : transitionManager(this)
504{
505}
506
507void QQuickPopupPrivate::init()
508{
509 Q_Q(QQuickPopup);
510 popupItem = new QQuickPopupItem(q);
511 popupItem->setVisible(false);
512 QObject::connect(popupItem, &QQuickControl::paddingChanged, q, &QQuickPopup::paddingChanged);
513 QObject::connect(popupItem, &QQuickControl::backgroundChanged, q, &QQuickPopup::backgroundChanged);
514 QObject::connect(popupItem, &QQuickControl::contentItemChanged, q, &QQuickPopup::contentItemChanged);
515 QObject::connect(popupItem, &QQuickControl::implicitContentWidthChanged, q, &QQuickPopup::implicitContentWidthChanged);
516 QObject::connect(popupItem, &QQuickControl::implicitContentHeightChanged, q, &QQuickPopup::implicitContentHeightChanged);
517 QObject::connect(popupItem, &QQuickControl::implicitBackgroundWidthChanged, q, &QQuickPopup::implicitBackgroundWidthChanged);
518 QObject::connect(popupItem, &QQuickControl::implicitBackgroundHeightChanged, q, &QQuickPopup::implicitBackgroundHeightChanged);
519}
520
521void QQuickPopupPrivate::closeOrReject()
522{
523 Q_Q(QQuickPopup);
524#if QT_CONFIG(quicktemplates2_container)
525 if (QQuickDialog *dialog = qobject_cast<QQuickDialog*>(q))
526 dialog->reject();
527 else
528#endif
529 q->close();
530 touchId = -1;
531}
532
533bool QQuickPopupPrivate::tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags)
534{
535 if (!interactive)
536 return false;
537
538 static const QQuickPopup::ClosePolicy outsideFlags = QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnReleaseOutside;
539 static const QQuickPopup::ClosePolicy outsideParentFlags = QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent;
540
541 const bool onOutside = closePolicy & (flags & outsideFlags);
542 const bool onOutsideParent = closePolicy & (flags & outsideParentFlags);
543
544 if ((onOutside && outsidePressed) || (onOutsideParent && outsideParentPressed)) {
545 if (!contains(pos) && (!dimmer || dimmer->contains(dimmer->mapFromScene(pos)))) {
546 if (!onOutsideParent || !parentItem || !parentItem->contains(parentItem->mapFromScene(pos))) {
547 closeOrReject();
548 return true;
549 }
550 }
551 }
552 return false;
553}
554
555bool QQuickPopupPrivate::contains(const QPointF &scenePos) const
556{
557 return popupItem->contains(popupItem->mapFromScene(scenePos));
558}
559
560#if QT_CONFIG(quicktemplates2_multitouch)
561bool QQuickPopupPrivate::acceptTouch(const QTouchEvent::TouchPoint &point)
562{
563 if (point.id() == touchId)
564 return true;
565
566 if (touchId == -1 && point.state() != QEventPoint::Released) {
567 touchId = point.id();
568 return true;
569 }
570
571 return false;
572}
573#endif
574
575bool QQuickPopupPrivate::blockInput(QQuickItem *item, const QPointF &point) const
576{
577 // don't propagate events within the popup beyond the overlay
578 if (popupItem->contains(popupItem->mapFromScene(point))
579 && item == QQuickOverlay::overlay(window, parentItem)) {
580 return true;
581 }
582
583 // don't block presses and releases
584 // a) outside a non-modal popup,
585 // b) to popup children/content, or
586 // c) outside a modal popups's background dimming
587
588 return modal && ((popupItem != item) && !popupItem->isAncestorOf(item)) && (!dimmer || dimmer->contains(dimmer->mapFromScene(point)));
589}
590
591bool QQuickPopupPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp)
592{
593 Q_UNUSED(timestamp);
594 pressPoint = point;
595 outsidePressed = !contains(point);
596
597 if (outsidePressed && parentItem) {
598 // Note that the parentItem (e.g a menuBarItem, in case of a MenuBar) will
599 // live inside another window when using popup windows. We therefore need to
600 // map to and from global.
601 const QPointF globalPoint = item->mapToGlobal(point);
602 const QPointF localPoint = parentItem->mapFromGlobal(globalPoint);
603 outsideParentPressed = !parentItem->contains(localPoint);
604 }
605
606 tryClose(point, QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
607 return blockInput(item, point);
608}
609
610bool QQuickPopupPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp)
611{
612 Q_UNUSED(timestamp);
613 return blockInput(item, point);
614}
615
616bool QQuickPopupPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
617{
618 Q_UNUSED(timestamp);
619 if (item != popupItem && !contains(pressPoint))
620 tryClose(point, QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent);
621 pressPoint = QPointF();
622 outsidePressed = false;
623 outsideParentPressed = false;
624 touchId = -1;
625 return blockInput(item, point);
626}
627
628void QQuickPopupPrivate::handleUngrab()
629{
630 Q_Q(QQuickPopup);
631 QQuickOverlay *overlay = QQuickOverlay::overlay(window, parentItem);
632 if (overlay) {
633 QQuickOverlayPrivate *p = QQuickOverlayPrivate::get(overlay);
634 if (p->mouseGrabberPopup == q)
635 p->mouseGrabberPopup = nullptr;
636 }
637 pressPoint = QPointF();
638 touchId = -1;
639}
640
641bool QQuickPopupPrivate::handleMouseEvent(QQuickItem *item, QMouseEvent *event)
642{
643 switch (event->type()) {
644 case QEvent::MouseButtonPress:
645 return handlePress(item, event->scenePosition(), event->timestamp());
646 case QEvent::MouseMove:
647 return handleMove(item, event->scenePosition(), event->timestamp());
648 case QEvent::MouseButtonRelease:
649 return handleRelease(item, event->scenePosition(), event->timestamp());
650 default:
651 Q_UNREACHABLE_RETURN(false);
652 }
653}
654
655bool QQuickPopupPrivate::handleHoverEvent(QQuickItem *item, QHoverEvent *event)
656{
657 switch (event->type()) {
658 case QEvent::HoverEnter:
659 case QEvent::HoverMove:
660 case QEvent::HoverLeave:
661 return blockInput(item, event->scenePosition());
662 default:
663 Q_UNREACHABLE_RETURN(false);
664 }
665}
666
667QMarginsF QQuickPopupPrivate::windowInsets() const
668{
669 // Don't honor negative insets on wayland. If we do,
670 // it would impact the popup window's geometry.
671 // We assume that the compositor will draw window decorations.
672#if QT_CONFIG(wayland)
673 if (QGuiApplication::platformName().startsWith(QLatin1String("wayland")))
674 return {0, 0, 0, 0};
675#endif
676 Q_Q(const QQuickPopup);
677 // If the popup has negative insets, it means that its background is pushed
678 // outside the bounds of the popup. This is fine when the popup is an item in the
679 // scene (Popup.Item), but will result in the background being clipped when using
680 // a window (Popup.Window). To avoid this, the window will been made bigger than
681 // the popup (according to the insets), to also include the part that ends up
682 // outside (which is usually a drop-shadow).
683 // Note that this also means that we need to take those extra margins into account
684 // whenever we resize or position the menu, so that the top-left of the popup ends
685 // up at the requested position, and not the top-left of the window.
686
687 const auto *popupItemPrivate = QQuickControlPrivate::get(popupItem);
688 if (!usePopupWindow() || (popupItemPrivate->background.isExecuting() && popupItemPrivate->background->clip())) {
689 // Items in the scene are allowed to draw out-of-bounds, so we don't
690 // need to do anything if we're not using popup windows. The same is
691 // also true for popup windows if the background is clipped.
692 return {0, 0, 0, 0};
693 }
694
695 return {
696 q->leftInset() < 0 ? -q->leftInset() : 0,
697 q->topInset() < 0 ? -q->topInset() : 0,
698 q->rightInset() < 0 ? -q->rightInset() : 0,
699 q->bottomInset() < 0 ? -q->bottomInset() : 0
700 };
701}
702
703QPointF QQuickPopupPrivate::windowInsetsTopLeft() const
704{
705 const QMarginsF windowMargins = windowInsets();
706 return {windowMargins.left(), windowMargins.top()};
707}
708
709void QQuickPopupPrivate::setEffectivePosFromWindowPos(const QPointF &windowPos)
710{
711 // Popup operates internally with three different positions; requested
712 // position, effective position, and window position. The first is the
713 // position requested by the application, and the second is where the popup
714 // is actually placed. The reason for placing it on a different position than
715 // the one requested, is to keep it inside the window (in case of Popup.Item),
716 // or the screen (in case of Popup.Window).
717 // Additionally, since a popup can set Qt::FramelessWindowHint and draw the
718 // window frame from the background delegate, the effective position in that
719 // case is adjusted to be the top-left corner of the background delegate, rather
720 // than the top-left corner of the window. This allowes the background delegate
721 // to render a drop-shadow between the edge of the window and the background frame.
722 // Finally, the window position is the actual position of the window, including
723 // any drop-shadow effects. This posision can be calculated by taking
724 // the effective position and subtract the dropShadowOffset().
725 Q_Q(QQuickPopup);
726 const QPointF oldEffectivePos = effectivePos;
727 effectivePos = windowPos + windowInsetsTopLeft();
728 if (!qFuzzyCompare(oldEffectivePos.x(), effectivePos.x()))
729 emit q->xChanged();
730 if (!qFuzzyCompare(oldEffectivePos.y(), effectivePos.y()))
731 emit q->yChanged();
732}
733
734#if QT_CONFIG(quicktemplates2_multitouch)
735bool QQuickPopupPrivate::handleTouchEvent(QQuickItem *item, QTouchEvent *event)
736{
737 switch (event->type()) {
738 case QEvent::TouchBegin:
739 case QEvent::TouchUpdate:
740 case QEvent::TouchEnd:
741 for (const QTouchEvent::TouchPoint &point : event->points()) {
742 if (event->type() != QEvent::TouchEnd && !acceptTouch(point))
743 return blockInput(item, point.position());
744
745 switch (point.state()) {
746 case QEventPoint::Pressed:
747 return handlePress(item, point.scenePosition(), event->timestamp());
748 case QEventPoint::Updated:
749 return handleMove(item, point.scenePosition(), event->timestamp());
750 case QEventPoint::Released:
751 return handleRelease(item, point.scenePosition(), event->timestamp());
752 default:
753 break;
754 }
755 }
756 break;
757
758 case QEvent::TouchCancel:
759 handleUngrab();
760 break;
761
762 default:
763 break;
764 }
765
766 return false;
767}
768#endif
769
770bool QQuickPopupPrivate::prepareEnterTransition()
771{
772 Q_Q(QQuickPopup);
773 if (!window) {
774 qmlWarning(q) << "cannot find any window to open popup in.";
775 return false;
776 }
777
778 if (transitionState == EnterTransition && transitionManager.isRunning())
779 return false;
780
781 if (transitionState != EnterTransition) {
782 const QPointer<QQuickItem> lastActiveFocusItem = window->activeFocusItem();
783 visible = true;
784 adjustPopupItemParentAndWindow();
785 if (dim)
786 createOverlay();
787 showDimmer();
788 emit q->aboutToShow();
789 transitionState = EnterTransition;
790 getPositioner()->setParentItem(parentItem);
791 emit q->visibleChanged();
792
793 if (lastActiveFocusItem) {
794 this->lastActiveFocusItem = lastActiveFocusItem;
795 if (auto *overlay = QQuickOverlay::overlay(window, parentItem)) {
796 auto *overlayPrivate = QQuickOverlayPrivate::get(overlay);
797 if (overlayPrivate->lastActiveFocusItem.isNull() && !popupItem->isAncestorOf(lastActiveFocusItem)) {
798 overlayPrivate->lastActiveFocusItem = lastActiveFocusItem;
799 overlayPrivate->lastActiveFocusItemPopup = q;
800 }
801 }
802 }
803
804 if (focus)
805 popupItem->setFocus(true, Qt::PopupFocusReason);
806 }
807 return true;
808}
809
810bool QQuickPopupPrivate::prepareExitTransition()
811{
812 Q_Q(QQuickPopup);
813 if (transitionState == ExitTransition && transitionManager.isRunning())
814 return false;
815
816 Q_ASSERT(popupItem);
817
818 // We need to cache the original scale and opacity values so we can reset it after
819 // the exit transition is done so they have the original values again
820 prevScale = popupItem->scale();
821 prevOpacity = popupItem->opacity();
822
823 if (transitionState != ExitTransition) {
824 // The setFocus(false) call below removes any active focus before we're
825 // able to check it in finalizeExitTransition.
826 if (!hadActiveFocusBeforeExitTransition) {
827 const auto *da = QQuickItemPrivate::get(popupItem)->deliveryAgentPrivate();
828 hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus() || (da && da->focusTargetItem() == popupItem);
829 }
830 if (focus)
831 popupItem->setFocus(false, Qt::PopupFocusReason);
832 transitionState = ExitTransition;
833 hideDimmer();
834 emit q->aboutToHide();
835 emit q->openedChanged();
836 }
837 return true;
838}
839
840void QQuickPopupPrivate::finalizeEnterTransition()
841{
842 Q_Q(QQuickPopup);
843 transitionState = NoTransition;
844 reposition();
845 emit q->openedChanged();
846 opened();
847}
848
849void QQuickPopupPrivate::finalizeExitTransition()
850{
851 Q_Q(QQuickPopup);
852 getPositioner()->setParentItem(nullptr);
853 if (popupItem) {
854 popupItem->setParentItem(nullptr);
855 popupItem->setVisible(false);
856 }
857 destroyDimmer();
858
859 if (auto *overlay = QQuickOverlay::overlay(window, parentItem)) {
860 auto *overlayPrivate = QQuickOverlayPrivate::get(overlay);
861 const auto stackingOrderPopups = overlayPrivate->stackingOrderPopups();
862 // Reset the last active focus item in the overlay when this popup exit
863 bool resetLastActiveFocusItem = (overlayPrivate->lastActiveFocusItemPopup == q);
864 if (resetLastActiveFocusItem) {
865 /**
866 * Check for popups in the stack that:
867 * 1. Are not in an exit transition.
868 * 2. Contain a saved last active focus item (from the window).
869 * If found, update the overlay's focus reference to this item and
870 * prevent a reset. This ensures focus returns to the correct
871 * pre-popup element once the window clears.
872 */
873 for (auto popup : stackingOrderPopups) {
874 if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition) {
875 if (auto savedFocusItem = QQuickPopupPrivate::get(popup)->lastActiveFocusItem) {
876 if (!qobject_cast<QQuickRootItem *>(savedFocusItem) && savedFocusItem != popupItem
877 && !popupItem->isAncestorOf(savedFocusItem)) {
878 overlayPrivate->lastActiveFocusItem = savedFocusItem;
879 }
880 overlayPrivate->lastActiveFocusItemPopup = popup;
881 resetLastActiveFocusItem = false;
882 break;
883 }
884 }
885 }
886 }
887
888 // restore focus to the next popup in chain, or to the window content if there are no other popups open
889 if (hadActiveFocusBeforeExitTransition) {
890 QQuickPopup *nextFocusPopup = nullptr;
891 for (auto popup : stackingOrderPopups) {
892 // only pick a popup that is focused but has not already been activated
893 if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition
894 && popup->hasFocus() && !popup->hasActiveFocus()) {
895 nextFocusPopup = popup;
896 break;
897 }
898 }
899 if (nextFocusPopup) {
900 nextFocusPopup->forceActiveFocus(Qt::PopupFocusReason);
901 } else {
902 auto *appWindow = qobject_cast<QQuickApplicationWindow*>(window);
903 auto *contentItem = appWindow ? appWindow->contentItem() : window->contentItem();
904 if (!contentItem->scopedFocusItem()
905 && !overlayPrivate->lastActiveFocusItem.isNull()) {
906 // The last active focus item may have lost focus not just for
907 // itself but for its entire focus chain, so force active focus.
908 overlayPrivate->lastActiveFocusItem->forceActiveFocus(Qt::OtherFocusReason);
909 } else {
910 contentItem->setFocus(true, Qt::PopupFocusReason);
911 }
912 }
913 }
914
915 // Clear the overlay's saved focus if this popup was the one that set it
916 if (resetLastActiveFocusItem || stackingOrderPopups.isEmpty()) {
917 overlayPrivate->lastActiveFocusItem = nullptr;
918 overlayPrivate->lastActiveFocusItemPopup = nullptr;
919 }
920 }
921
922 visible = false;
923 adjustPopupItemParentAndWindow();
924 transitionState = NoTransition;
925 hadActiveFocusBeforeExitTransition = false;
926 lastActiveFocusItem = nullptr;
927 emit q->visibleChanged();
928 emit q->closed();
929#if QT_CONFIG(accessibility)
930 const auto type = q->effectiveAccessibleRole() == QAccessible::PopupMenu
931 ? QAccessible::PopupMenuEnd
932 : QAccessible::DialogEnd;
933 QAccessibleEvent ev(q->popupItem(), type);
934 QAccessible::updateAccessibility(&ev);
935#endif
936 if (popupItem) {
937 popupItem->setScale(prevScale);
938 popupItem->setOpacity(prevOpacity);
939 }
940}
941
942void QQuickPopupPrivate::opened()
943{
944 Q_Q(QQuickPopup);
945 emit q->opened();
946#if QT_CONFIG(accessibility)
947 const auto type = q->effectiveAccessibleRole() == QAccessible::PopupMenu
948 ? QAccessible::PopupMenuStart
949 : QAccessible::DialogStart;
950 QAccessibleEvent ev(q->popupItem(), type);
951 QAccessible::updateAccessibility(&ev);
952#endif
953}
954
955Qt::WindowFlags QQuickPopupPrivate::popupWindowFlags() const
956{
957 return windowFlags;
958}
959
960void QQuickPopupPrivate::setPopupWindowFlags(Qt::WindowFlags flags)
961{
962 windowFlags = flags;
963}
964
965QMarginsF QQuickPopupPrivate::getMargins() const
966{
967 Q_Q(const QQuickPopup);
968 return QMarginsF(q->leftMargin(), q->topMargin(), q->rightMargin(), q->bottomMargin());
969}
970
971void QQuickPopupPrivate::setTopMargin(qreal value, bool reset)
972{
973 Q_Q(QQuickPopup);
974 qreal oldMargin = q->topMargin();
975 topMargin = value;
976 hasTopMargin = !reset;
977 if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
978 emit q->topMarginChanged();
979 q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
980 QMarginsF(leftMargin, oldMargin, rightMargin, bottomMargin));
981 }
982}
983
984void QQuickPopupPrivate::setLeftMargin(qreal value, bool reset)
985{
986 Q_Q(QQuickPopup);
987 qreal oldMargin = q->leftMargin();
988 leftMargin = value;
989 hasLeftMargin = !reset;
990 if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
991 emit q->leftMarginChanged();
992 q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
993 QMarginsF(oldMargin, topMargin, rightMargin, bottomMargin));
994 }
995}
996
997void QQuickPopupPrivate::setRightMargin(qreal value, bool reset)
998{
999 Q_Q(QQuickPopup);
1000 qreal oldMargin = q->rightMargin();
1001 rightMargin = value;
1002 hasRightMargin = !reset;
1003 if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
1004 emit q->rightMarginChanged();
1005 q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
1006 QMarginsF(leftMargin, topMargin, oldMargin, bottomMargin));
1007 }
1008}
1009
1010void QQuickPopupPrivate::setBottomMargin(qreal value, bool reset)
1011{
1012 Q_Q(QQuickPopup);
1013 qreal oldMargin = q->bottomMargin();
1014 bottomMargin = value;
1015 hasBottomMargin = !reset;
1016 if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
1017 emit q->bottomMarginChanged();
1018 q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
1019 QMarginsF(leftMargin, topMargin, rightMargin, oldMargin));
1020 }
1021}
1022
1023/*!
1024 \since QtQuick.Controls 2.5 (Qt 5.12)
1025 \qmlproperty Item QtQuick.Controls::Popup::anchors.centerIn
1026
1027 Anchors provide a way to position an item by specifying its
1028 relationship with other items.
1029
1030 A common use case is to center a popup within its parent. One way to do
1031 this is with the \l[QtQuick]{Item::}{x} and \l[QtQuick]{Item::}{y} properties. Anchors offer
1032 a more convenient approach:
1033
1034 \qml
1035 Pane {
1036 // ...
1037
1038 Popup {
1039 anchors.centerIn: parent
1040 }
1041 }
1042 \endqml
1043
1044 It is also possible to center the popup in the window by using \l Overlay:
1045
1046 \snippet qtquickcontrols-popup.qml centerIn
1047
1048 This makes it easy to center a popup in the window from any component.
1049
1050 \note Popups can only be centered within their immediate parent or
1051 the window overlay; trying to center in other items will produce a warning.
1052
1053 \sa {Popup Positioning}, {Item::}{anchors}, {Using Qt Quick Controls types
1054 in property declarations}
1055*/
1056QQuickPopupAnchors *QQuickPopupPrivate::getAnchors()
1057{
1058 Q_Q(QQuickPopup);
1059 if (!anchors)
1060 anchors = new QQuickPopupAnchors(q);
1061 return anchors;
1062}
1063
1064QQuickPopupPositioner *QQuickPopupPrivate::getPositioner()
1065{
1066 Q_Q(QQuickPopup);
1067 if (!positioner)
1068 positioner = new QQuickPopupPositioner(q);
1069 return positioner;
1070}
1071
1072
1074{
1075 Q_OBJECT
1076public:
1078 : m_func(func)
1079 {
1080 w->installEventFilter(this);
1081 }
1082protected:
1085 if (event->type() == QEvent::Expose)
1086 m_func();
1087 return false;
1088 }
1089private:
1090 std::function<void()> m_func;
1091};
1092
1094{
1096 observer->disconnect();
1097 observer->deleteLater();
1098 }
1099};
1101
1102/*!
1103 \internal
1104 A popup's position is meant to be relative to its nearest parent item.
1105 If this item exists in another window, the position needs to be mapped between the windows.
1106 We use mapToGlobal(QPointF) to figure out where to position the popup window.
1107 However, if mapToGlobal(QPointF) is called before the parent window is exposed,
1108 it will on Windows and X11 assume that the parent windows position is (0,0).
1109 This means that the popup window's position will usually be wrong, when it's
1110 opened at the same time as the parent window.
1111 To work around this issue, we wait for the parent window to be exposed, before opening the popup window.
1112 */
1113void openPopup(QQuickPopupPrivate *d)
1114{
1115#if defined(Q_OS_MACOS)
1116 d->transitionManager.transitionEnter();
1117#else
1118 const auto callPrepareEnterTransition = [d]() {
1119 d->transitionManager.transitionEnter();
1120 s_windowExposedObserver.release();
1121 };
1122 if (d->usePopupWindow() && d->window->isVisible() && !d->window->isExposed())
1123 s_windowExposedObserver.reset(new QWindowExposedObserver(d->window, callPrepareEnterTransition));
1124 else
1125 callPrepareEnterTransition();
1126#endif
1127}
1128
1129void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow)
1130{
1131 Q_Q(QQuickPopup);
1132 if (window == newWindow)
1133 return;
1134
1135 if (window) {
1136 QQuickOverlay *overlay = QQuickOverlay::overlay(window, parentItem);
1137 if (overlay)
1138 QQuickOverlayPrivate::get(overlay)->removePopup(q);
1139
1140 // Interacting with Popups in async Loaders (QTBUG-139306) would cause crashes
1141 // because the popup's window was null. We can avoid this by unparenting the popupItem,
1142 // which removes it from stackingOrderPopups and hence excludes it from receiving events.
1143 if (!newWindow && popupItem)
1144 popupItem->setParentItem(nullptr);
1145 }
1146
1147 window = newWindow;
1148
1149 if (newWindow) {
1150 QQuickOverlay *overlay = QQuickOverlay::overlay(newWindow, parentItem);
1151 if (overlay)
1152 QQuickOverlayPrivate::get(overlay)->addPopup(q);
1153
1154 QQuickControlPrivate *p = QQuickControlPrivate::get(popupItem);
1155 p->resolveFont();
1156 if (QQuickApplicationWindow *appWindow = qobject_cast<QQuickApplicationWindow *>(newWindow))
1157 p->updateLocale(appWindow->locale(), false); // explicit=false
1158 }
1159
1160 emit q->windowChanged(newWindow);
1161
1162 if (complete && visible && window)
1163 openPopup(this);
1164}
1165
1166void QQuickPopupPrivate::itemDestroyed(QQuickItem *item)
1167{
1168 Q_Q(QQuickPopup);
1169 if (item == parentItem)
1170 q->setParentItem(nullptr);
1171}
1172
1173void QQuickPopupPrivate::reposition()
1174{
1175 getPositioner()->reposition();
1176}
1177
1178QPalette QQuickPopupPrivate::defaultPalette() const
1179{
1180 return QQuickTheme::palette(QQuickTheme::System);
1181}
1182
1183QQuickPopup::PopupType QQuickPopupPrivate::resolvedPopupType() const
1184{
1185 // Whether or not the resolved popup type ends up the same as the preferred popup type
1186 // depends on platform capabilities, the popup subclass, and sometimes also the location
1187 // of the popup in the parent hierarchy (menus). This function can therefore be overridden
1188 // to return the actual popup type that should be used, based on the knowledge the popup
1189 // has just before it's about to be shown.
1190
1191 // PopupType::Native is not directly supported by QQuickPopup (only by subclasses).
1192 // So for that case, we fall back to use PopupType::Window, if supported.
1193 if (popupType == QQuickPopup::PopupType::Window
1194 || popupType == QQuickPopup::PopupType::Native) {
1195 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::Capability::MultipleWindows))
1196 return QQuickPopup::PopupType::Window;
1197 }
1198
1199 return QQuickPopup::PopupType::Item;
1200}
1201
1202bool QQuickPopupPrivate::usePopupWindow() const
1203{
1204 return resolvedPopupType() == QQuickPopup::PopupType::Window;
1205}
1206
1207void QQuickPopupPrivate::adjustPopupItemParentAndWindow()
1208{
1209 Q_Q(QQuickPopup);
1210 QQuickOverlay *overlay = QQuickOverlay::overlay(window, parentItem);
1211
1212 if (visible && popupWindowDirty) {
1213 popupItem->setParentItem(overlay);
1214 if (popupWindow) {
1215 popupWindow->deleteLater();
1216 popupWindow = nullptr;
1217 }
1218 popupWindowDirty = false;
1219 }
1220
1221 if (usePopupWindow()) {
1222 if (visible) {
1223 if (!popupWindow) {
1224 popupWindow = new QQuickPopupWindow(q, window);
1225 // Changing the visual parent can cause the popup item's implicit width/height to change.
1226 // We store the initial size here first, to ensure that we're resizing the window to the correct size.
1227 const qreal initialWidth = popupItem->width() + windowInsets().left() + windowInsets().right();
1228 const qreal initialHeight = popupItem->height() + windowInsets().top() + windowInsets().bottom();
1229 popupItem->setParentItem(popupWindow->contentItem());
1230 popupWindow->resize(qCeil(initialWidth), qCeil(initialHeight));
1231 if (popupWndModality != Qt::NonModal)
1232 popupWindow->setModality(popupWndModality);
1233 else
1234 popupWindow->setModality(modal ? Qt::ApplicationModal : Qt::NonModal);
1235 popupItem->resetTitle();
1236 popupWindow->setTitle(title);
1237 }
1238 popupItem->setParentItem(popupWindow->contentItem());
1239 popupItem->forceActiveFocus(Qt::PopupFocusReason);
1240 }
1241 if (popupWindow && popupWindow->transientParent()) {
1242 auto *transientParentPriv = QQuickWindowPrivate::get(qobject_cast<QQuickWindow *>(popupWindow->transientParent()));
1243 if (!transientParentPriv->inDestructor)
1244 popupWindow->setVisible(visible);
1245 }
1246 } else {
1247 if (visible) {
1248 popupItem->setParentItem(overlay);
1249 const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
1250 // if there is a stack of popups, and the current top popup item belongs to an
1251 // ancestor of this popup, then make sure that this popup's item is at the top
1252 // of the stack.
1253 const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first();
1254 const QObject *ancestor = q;
1255 while (ancestor && topPopup) {
1256 if (ancestor == topPopup)
1257 break;
1258 ancestor = ancestor->parent();
1259 }
1260 if (topPopup && topPopup != q && ancestor) {
1261 QQuickItem *topPopupItem = popupStack.first()->popupItem();
1262 popupItem->stackAfter(topPopupItem);
1263 // If the popup doesn't have an explicit z value set, set it to be at least as
1264 // high as the current top popup item so that later opened popups are on top.
1265 if (!hasZ)
1266 popupItem->setZ(qMax(topPopupItem->z(), popupItem->z()));
1267 }
1268 q->setModal((popupWndModality != Qt::NonModal) || modal);
1269 }
1270
1271 popupItem->setTitle(title);
1272 }
1273 popupItem->setVisible(visible);
1274}
1275
1276QQuickItem *QQuickPopupPrivate::createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent) const
1277{
1278 QQuickItem *item = nullptr;
1279 if (component) {
1280 QQmlContext *context = component->creationContext();
1281 if (!context)
1282 context = qmlContext(popup);
1283 item = qobject_cast<QQuickItem*>(component->beginCreate(context));
1284 }
1285
1286 // when there is no overlay component available (with plain QQuickWindow),
1287 // use a plain QQuickItem as a fallback to block hover events
1288 if (!item && popup->isModal())
1289 item = new QQuickItem;
1290
1291 if (item) {
1292 item->setParentItem(parent);
1293 if (resolvedPopupType() != QQuickPopup::PopupType::Window)
1294 item->stackBefore(popup->popupItem());
1295 item->setZ(popup->z());
1296 // needed for the virtual keyboard to set a containment mask on the dimmer item
1297 qCDebug(lcDimmer) << "dimmer" << item << "registered with" << parent;
1298 parent->setProperty("_q_dimmerItem", QVariant::fromValue<QQuickItem*>(item));
1299 if (popup->isModal()) {
1300 item->setAcceptedMouseButtons(Qt::AllButtons);
1301#if QT_CONFIG(cursor)
1302 item->setCursor(Qt::ArrowCursor);
1303#endif
1304#if QT_CONFIG(quicktemplates2_hover)
1305 // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
1306 item->setAcceptHoverEvents(true);
1307 // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
1308 // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents);
1309#endif
1310 }
1311 if (component)
1312 component->completeCreate();
1313 }
1314 qCDebug(lcDimmer) << "finished creating dimmer from component" << component
1315 << "for popup" << popup << "with parent" << parent << "- item is:" << item;
1316 return item;
1317}
1318
1319void QQuickPopupPrivate::createOverlay()
1320{
1321 Q_Q(QQuickPopup);
1322 QQuickOverlay *overlay = QQuickOverlay::overlay(window, parentItem);
1323 if (!overlay)
1324 return;
1325
1326 QQmlComponent *component = nullptr;
1327 QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(qmlAttachedPropertiesObject<QQuickOverlay>(q, false));
1328 if (overlayAttached)
1329 component = modal ? overlayAttached->modal() : overlayAttached->modeless();
1330
1331 if (!component)
1332 component = modal ? overlay->modal() : overlay->modeless();
1333
1334 if (!dimmer) {
1335 dimmer = createDimmer(component, q, overlay);
1336 if (!dimmer)
1337 return;
1338 // We cannot update explicitDimmerOpacity when dimmer's opacity changes,
1339 // as it is expected to do so when we fade the dimmer in and out in
1340 // show/hideDimmer, and any binding of the dimmer's opacity will be
1341 // implicitly broken anyway.
1342 explicitDimmerOpacity = dimmer->opacity();
1343 // initially fully transparent, showDimmer fades the dimmer in.
1344 dimmer->setOpacity(0);
1345 if (q->isVisible())
1346 showDimmer();
1347 }
1348 resizeDimmer();
1349}
1350
1351void QQuickPopupPrivate::destroyDimmer()
1352{
1353 if (dimmer) {
1354 qCDebug(lcDimmer) << "destroying dimmer" << dimmer;
1355 if (QObject *dimmerParentItem = dimmer->parentItem()) {
1356 if (dimmerParentItem->property("_q_dimmerItem").value<QQuickItem*>() == dimmer)
1357 dimmerParentItem->setProperty("_q_dimmerItem", QVariant());
1358 }
1359 dimmer->setParentItem(nullptr);
1360 dimmer->deleteLater();
1361 dimmer = nullptr;
1362 }
1363}
1364
1365void QQuickPopupPrivate::toggleOverlay()
1366{
1367 destroyDimmer();
1368 if (dim)
1369 createOverlay();
1370}
1371
1372void QQuickPopupPrivate::updateContentPalettes(const QPalette& parentPalette)
1373{
1374 // Inherit parent palette to all child objects
1375 if (providesPalette())
1376 inheritPalette(parentPalette);
1377 // Inherit parent palette to items within popup (such as headers and footers)
1378 QQuickItemPrivate::get(popupItem)->updateChildrenPalettes(parentPalette);
1379}
1380
1381void QQuickPopupPrivate::updateChildrenPalettes(const QPalette& parentPalette)
1382{
1383 updateContentPalettes(parentPalette);
1384}
1385
1386void QQuickPopupPrivate::showDimmer()
1387{
1388 // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
1389 if (dim && dimmer)
1390 QQmlProperty::write(dimmer, QStringLiteral("opacity"), explicitDimmerOpacity);
1391}
1392
1393void QQuickPopupPrivate::hideDimmer()
1394{
1395 // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
1396 if (dim && dimmer)
1397 QQmlProperty::write(dimmer, QStringLiteral("opacity"), 0.0);
1398}
1399
1400void QQuickPopupPrivate::resizeDimmer()
1401{
1402 if (!dimmer)
1403 return;
1404
1405 const QQuickOverlay *overlay = QQuickOverlay::overlay(window, parentItem);
1406
1407 qreal w = overlay ? overlay->width() : 0;
1408 qreal h = overlay ? overlay->height() : 0;
1409 dimmer->setSize(QSizeF(w, h));
1410}
1411
1412QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup)
1413 : popup(popup)
1414{
1415}
1416
1417void QQuickPopupTransitionManager::transitionEnter()
1418{
1419 if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
1420 cancel();
1421
1422 if (!popup->prepareEnterTransition())
1423 return;
1424
1425 if (popup->window)
1426 transition(popup->enterActions, popup->enter, popup->q_func());
1427 else
1428 finished();
1429}
1430
1431void QQuickPopupTransitionManager::transitionExit()
1432{
1433 if (!popup->prepareExitTransition())
1434 return;
1435
1436 if (popup->window)
1437 transition(popup->exitActions, popup->exit, popup->q_func());
1438 else
1439 finished();
1440}
1441
1442void QQuickPopupTransitionManager::finished()
1443{
1444 if (popup->transitionState == QQuickPopupPrivate::EnterTransition)
1445 popup->finalizeEnterTransition();
1446 else if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
1447 popup->finalizeExitTransition();
1448}
1449
1450QQuickPopup::QQuickPopup(QObject *parent)
1451 : QObject(*(new QQuickPopupPrivate), parent)
1452{
1453 Q_D(QQuickPopup);
1454 d->init();
1455 // By default, allow popup to move beyond window edges
1456 d->relaxEdgeConstraint = true;
1457}
1458
1459QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent)
1460 : QObject(dd, parent)
1461{
1462 Q_D(QQuickPopup);
1463 d->init();
1464}
1465
1466QQuickPopup::~QQuickPopup()
1467{
1468 Q_D(QQuickPopup);
1469 d->inDestructor = true;
1470
1471 QQuickItem *currentContentItem = d->popupItem->d_func()->contentItem.data();
1472 if (currentContentItem) {
1473 disconnect(currentContentItem, &QQuickItem::childrenChanged,
1474 this, &QQuickPopup::contentChildrenChanged);
1475 }
1476
1477 setParentItem(nullptr);
1478
1479 // If the popup is destroyed before the exit transition finishes,
1480 // the necessary cleanup (removing modal dimmers that block mouse events,
1481 // emitting closed signal, etc.) won't happen. That's why we do it manually here.
1482 if (d->transitionState == QQuickPopupPrivate::ExitTransition && d->transitionManager.isRunning())
1483 d->finalizeExitTransition();
1484
1485 delete d->popupItem;
1486 d->popupItem = nullptr;
1487 delete d->positioner;
1488 d->positioner = nullptr;
1489 if (d->popupWindow)
1490 delete d->popupWindow;
1491 d->popupWindow = nullptr;
1492}
1493
1494/*!
1495 \qmlmethod void QtQuick.Controls::Popup::open()
1496
1497 Opens the popup.
1498
1499 \sa visible
1500*/
1501void QQuickPopup::open()
1502{
1503 setVisible(true);
1504}
1505
1506/*!
1507 \qmlmethod void QtQuick.Controls::Popup::close()
1508
1509 Closes the popup.
1510
1511 \sa visible
1512*/
1513void QQuickPopup::close()
1514{
1515 setVisible(false);
1516}
1517
1518/*!
1519 \qmlproperty real QtQuick.Controls::Popup::x
1520
1521 This property holds the x-coordinate of the popup.
1522
1523 \sa y, z
1524*/
1525qreal QQuickPopup::x() const
1526{
1527 return d_func()->effectivePos.x();
1528}
1529
1530void QQuickPopup::setX(qreal x)
1531{
1532 Q_D(QQuickPopup);
1533 setPosition(QPointF(x, d->y));
1534}
1535
1536/*!
1537 \qmlproperty real QtQuick.Controls::Popup::y
1538
1539 This property holds the y-coordinate of the popup.
1540
1541 \sa x, z
1542*/
1543qreal QQuickPopup::y() const
1544{
1545 return d_func()->effectivePos.y();
1546}
1547
1548void QQuickPopup::setY(qreal y)
1549{
1550 Q_D(QQuickPopup);
1551 setPosition(QPointF(d->x, y));
1552}
1553
1554QPointF QQuickPopup::position() const
1555{
1556 return d_func()->effectivePos;
1557}
1558
1559void QQuickPopup::setPosition(const QPointF &pos)
1560{
1561 Q_D(QQuickPopup);
1562 const bool xChange = !qFuzzyCompare(d->x, pos.x());
1563 const bool yChange = !qFuzzyCompare(d->y, pos.y());
1564 if (!xChange && !yChange)
1565 return;
1566
1567 d->x = pos.x();
1568 d->y = pos.y();
1569 if (d->popupItem->isVisible()) {
1570 d->reposition();
1571 } else {
1572 if (xChange)
1573 emit xChanged();
1574 if (yChange)
1575 emit yChanged();
1576 }
1577}
1578
1579/*!
1580 \qmlproperty real QtQuick.Controls::Popup::z
1581
1582 This property holds the z-value of the popup. Z-value determines
1583 the stacking order of popups.
1584
1585 If two visible popups have the same z-value, the last one that
1586 was opened will be on top.
1587
1588 If a popup has no explicitly set z-value when opened, and is a child
1589 of an already open popup, then it will be stacked on top of its parent.
1590 This ensures that children are never hidden under their parents.
1591
1592 If the popup has its own window, the z-value will determine the window
1593 stacking order instead.
1594
1595 The default z-value is \c 0.
1596
1597 \sa x, y
1598*/
1599qreal QQuickPopup::z() const
1600{
1601 Q_D(const QQuickPopup);
1602 return d->popupItem->z();
1603}
1604
1605void QQuickPopup::setZ(qreal z)
1606{
1607 Q_D(QQuickPopup);
1608 d->hasZ = true;
1609 bool previousZ = d->popupWindow ? d->popupWindow->z() : d->popupItem->z();
1610 if (qFuzzyCompare(z, previousZ))
1611 return;
1612 if (d->popupWindow)
1613 d->popupWindow->setZ(z);
1614 else
1615 d->popupItem->setZ(z);
1616 emit zChanged();
1617}
1618
1619void QQuickPopup::resetZ()
1620{
1621 Q_D(QQuickPopup);
1622 setZ(0);
1623 d->hasZ = false;
1624}
1625
1626/*!
1627 \qmlproperty real QtQuick.Controls::Popup::width
1628
1629 This property holds the width of the popup.
1630*/
1631qreal QQuickPopup::width() const
1632{
1633 Q_D(const QQuickPopup);
1634 return d->popupItem->width();
1635}
1636
1637void QQuickPopup::setWidth(qreal width)
1638{
1639 Q_D(QQuickPopup);
1640 d->hasWidth = true;
1641
1642 // QQuickPopupWindow::setWidth() triggers a window resize event.
1643 // This will cause QQuickPopupWindow::resizeEvent() to resize
1644 // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
1645 // which emits widthChanged().
1646
1647 if (d->popupWindow)
1648 d->popupWindow->setWidth(width + d->windowInsets().left() + d->windowInsets().right());
1649 else
1650 d->popupItem->setWidth(width);
1651}
1652
1653void QQuickPopup::resetWidth()
1654{
1655 Q_D(QQuickPopup);
1656 if (!d->hasWidth)
1657 return;
1658
1659 d->hasWidth = false;
1660 d->popupItem->resetWidth();
1661 if (d->popupItem->isVisible())
1662 d->reposition();
1663}
1664
1665/*!
1666 \qmlproperty real QtQuick.Controls::Popup::height
1667
1668 This property holds the height of the popup.
1669*/
1670qreal QQuickPopup::height() const
1671{
1672 Q_D(const QQuickPopup);
1673 return d->popupItem->height();
1674}
1675
1676void QQuickPopup::setHeight(qreal height)
1677{
1678 Q_D(QQuickPopup);
1679 d->hasHeight = true;
1680
1681 // QQuickPopupWindow::setHeight() triggers a window resize event.
1682 // This will cause QQuickPopupWindow::resizeEvent() to resize
1683 // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
1684 // which emits heightChanged().
1685
1686 if (d->popupWindow)
1687 d->popupWindow->setHeight(height + d->windowInsets().top() + d->windowInsets().bottom());
1688 else
1689 d->popupItem->setHeight(height);
1690}
1691
1692void QQuickPopup::resetHeight()
1693{
1694 Q_D(QQuickPopup);
1695 if (!d->hasHeight)
1696 return;
1697
1698 d->hasHeight = false;
1699 d->popupItem->resetHeight();
1700 if (d->popupItem->isVisible())
1701 d->reposition();
1702}
1703
1704/*!
1705 \qmlproperty real QtQuick.Controls::Popup::implicitWidth
1706
1707 This property holds the implicit width of the popup.
1708*/
1709qreal QQuickPopup::implicitWidth() const
1710{
1711 Q_D(const QQuickPopup);
1712 return d->popupItem->implicitWidth();
1713}
1714
1715void QQuickPopup::setImplicitWidth(qreal width)
1716{
1717 Q_D(QQuickPopup);
1718 d->popupItem->setImplicitWidth(width);
1719}
1720
1721/*!
1722 \qmlproperty real QtQuick.Controls::Popup::implicitHeight
1723
1724 This property holds the implicit height of the popup.
1725*/
1726qreal QQuickPopup::implicitHeight() const
1727{
1728 Q_D(const QQuickPopup);
1729 return d->popupItem->implicitHeight();
1730}
1731
1732void QQuickPopup::setImplicitHeight(qreal height)
1733{
1734 Q_D(QQuickPopup);
1735 d->popupItem->setImplicitHeight(height);
1736}
1737
1738/*!
1739 \qmlproperty real QtQuick.Controls::Popup::contentWidth
1740
1741 This property holds the content width. It is used for calculating the
1742 total implicit width of the Popup.
1743
1744 For more information, see \l {Popup Sizing}.
1745
1746 \sa contentHeight
1747*/
1748qreal QQuickPopup::contentWidth() const
1749{
1750 Q_D(const QQuickPopup);
1751 return d->popupItem->contentWidth();
1752}
1753
1754void QQuickPopup::setContentWidth(qreal width)
1755{
1756 Q_D(QQuickPopup);
1757 d->popupItem->setContentWidth(width);
1758}
1759
1760/*!
1761 \qmlproperty real QtQuick.Controls::Popup::contentHeight
1762
1763 This property holds the content height. It is used for calculating the
1764 total implicit height of the Popup.
1765
1766 For more information, see \l {Popup Sizing}.
1767
1768 \sa contentWidth
1769*/
1770qreal QQuickPopup::contentHeight() const
1771{
1772 Q_D(const QQuickPopup);
1773 return d->popupItem->contentHeight();
1774}
1775
1776void QQuickPopup::setContentHeight(qreal height)
1777{
1778 Q_D(QQuickPopup);
1779 d->popupItem->setContentHeight(height);
1780}
1781
1782/*!
1783 \qmlproperty real QtQuick.Controls::Popup::availableWidth
1784 \readonly
1785
1786 This property holds the width available to the \l contentItem after
1787 deducting horizontal padding from the \l {Item::}{width} of the popup.
1788
1789 \sa padding, leftPadding, rightPadding
1790*/
1791qreal QQuickPopup::availableWidth() const
1792{
1793 Q_D(const QQuickPopup);
1794 return d->popupItem->availableWidth();
1795}
1796
1797/*!
1798 \qmlproperty real QtQuick.Controls::Popup::availableHeight
1799 \readonly
1800
1801 This property holds the height available to the \l contentItem after
1802 deducting vertical padding from the \l {Item::}{height} of the popup.
1803
1804 \sa padding, topPadding, bottomPadding
1805*/
1806qreal QQuickPopup::availableHeight() const
1807{
1808 Q_D(const QQuickPopup);
1809 return d->popupItem->availableHeight();
1810}
1811
1812/*!
1813 \since QtQuick.Controls 2.1 (Qt 5.8)
1814 \qmlproperty real QtQuick.Controls::Popup::spacing
1815
1816 This property holds the spacing.
1817
1818 Spacing is useful for popups that have multiple or repetitive building
1819 blocks. For example, some styles use spacing to determine the distance
1820 between the header, content, and footer of \l Dialog. Spacing is not
1821 enforced by Popup, so each style may interpret it differently, and some
1822 may ignore it altogether.
1823*/
1824qreal QQuickPopup::spacing() const
1825{
1826 Q_D(const QQuickPopup);
1827 return d->popupItem->spacing();
1828}
1829
1830void QQuickPopup::setSpacing(qreal spacing)
1831{
1832 Q_D(QQuickPopup);
1833 d->popupItem->setSpacing(spacing);
1834}
1835
1836void QQuickPopup::resetSpacing()
1837{
1838 setSpacing(0);
1839}
1840
1841/*!
1842 \qmlproperty real QtQuick.Controls::Popup::margins
1843
1844 This property holds the distance between the edges of the popup and the
1845 edges of its window.
1846
1847 A popup with negative margins is not pushed within the bounds
1848 of the enclosing window. The default value is \c -1.
1849
1850 \sa topMargin, leftMargin, rightMargin, bottomMargin, {Popup Layout}
1851*/
1852qreal QQuickPopup::margins() const
1853{
1854 Q_D(const QQuickPopup);
1855 return d->margins;
1856}
1857
1858void QQuickPopup::setMargins(qreal margins)
1859{
1860 Q_D(QQuickPopup);
1861 if (qFuzzyCompare(d->margins, margins))
1862 return;
1863 QMarginsF oldMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
1864 d->margins = margins;
1865 emit marginsChanged();
1866 QMarginsF newMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
1867 if (!qFuzzyCompare(newMargins.top(), oldMargins.top()))
1868 emit topMarginChanged();
1869 if (!qFuzzyCompare(newMargins.left(), oldMargins.left()))
1870 emit leftMarginChanged();
1871 if (!qFuzzyCompare(newMargins.right(), oldMargins.right()))
1872 emit rightMarginChanged();
1873 if (!qFuzzyCompare(newMargins.bottom(), oldMargins.bottom()))
1874 emit bottomMarginChanged();
1875 marginsChange(newMargins, oldMargins);
1876}
1877
1878void QQuickPopup::resetMargins()
1879{
1880 setMargins(-1);
1881}
1882
1883/*!
1884 \qmlproperty real QtQuick.Controls::Popup::topMargin
1885
1886 This property holds the distance between the top edge of the popup and
1887 the top edge of its window.
1888
1889 A popup with a negative top margin is not pushed within the top edge
1890 of the enclosing window. The default value is \c -1.
1891
1892 \sa margins, bottomMargin, {Popup Layout}
1893*/
1894qreal QQuickPopup::topMargin() const
1895{
1896 Q_D(const QQuickPopup);
1897 if (d->hasTopMargin)
1898 return d->topMargin;
1899 return d->margins;
1900}
1901
1902void QQuickPopup::setTopMargin(qreal margin)
1903{
1904 Q_D(QQuickPopup);
1905 d->setTopMargin(margin);
1906}
1907
1908void QQuickPopup::resetTopMargin()
1909{
1910 Q_D(QQuickPopup);
1911 d->setTopMargin(-1, true);
1912}
1913
1914/*!
1915 \qmlproperty real QtQuick.Controls::Popup::leftMargin
1916
1917 This property holds the distance between the left edge of the popup and
1918 the left edge of its window.
1919
1920 A popup with a negative left margin is not pushed within the left edge
1921 of the enclosing window. The default value is \c -1.
1922
1923 \sa margins, rightMargin, {Popup Layout}
1924*/
1925qreal QQuickPopup::leftMargin() const
1926{
1927 Q_D(const QQuickPopup);
1928 if (d->hasLeftMargin)
1929 return d->leftMargin;
1930 return d->margins;
1931}
1932
1933void QQuickPopup::setLeftMargin(qreal margin)
1934{
1935 Q_D(QQuickPopup);
1936 d->setLeftMargin(margin);
1937}
1938
1939void QQuickPopup::resetLeftMargin()
1940{
1941 Q_D(QQuickPopup);
1942 d->setLeftMargin(-1, true);
1943}
1944
1945/*!
1946 \qmlproperty real QtQuick.Controls::Popup::rightMargin
1947
1948 This property holds the distance between the right edge of the popup and
1949 the right edge of its window.
1950
1951 A popup with a negative right margin is not pushed within the right edge
1952 of the enclosing window. The default value is \c -1.
1953
1954 \sa margins, leftMargin, {Popup Layout}
1955*/
1956qreal QQuickPopup::rightMargin() const
1957{
1958 Q_D(const QQuickPopup);
1959 if (d->hasRightMargin)
1960 return d->rightMargin;
1961 return d->margins;
1962}
1963
1964void QQuickPopup::setRightMargin(qreal margin)
1965{
1966 Q_D(QQuickPopup);
1967 d->setRightMargin(margin);
1968}
1969
1970void QQuickPopup::resetRightMargin()
1971{
1972 Q_D(QQuickPopup);
1973 d->setRightMargin(-1, true);
1974}
1975
1976/*!
1977 \qmlproperty real QtQuick.Controls::Popup::bottomMargin
1978
1979 This property holds the distance between the bottom edge of the popup and
1980 the bottom edge of its window.
1981
1982 A popup with a negative bottom margin is not pushed within the bottom edge
1983 of the enclosing window. The default value is \c -1.
1984
1985 \sa margins, topMargin, {Popup Layout}
1986*/
1987qreal QQuickPopup::bottomMargin() const
1988{
1989 Q_D(const QQuickPopup);
1990 if (d->hasBottomMargin)
1991 return d->bottomMargin;
1992 return d->margins;
1993}
1994
1995void QQuickPopup::setBottomMargin(qreal margin)
1996{
1997 Q_D(QQuickPopup);
1998 d->setBottomMargin(margin);
1999}
2000
2001void QQuickPopup::resetBottomMargin()
2002{
2003 Q_D(QQuickPopup);
2004 d->setBottomMargin(-1, true);
2005}
2006
2007/*!
2008 \qmlproperty real QtQuick.Controls::Popup::padding
2009
2010 This property holds the default padding.
2011
2012 \include qquickpopup-padding.qdocinc
2013
2014 \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding
2015*/
2016qreal QQuickPopup::padding() const
2017{
2018 Q_D(const QQuickPopup);
2019 return d->popupItem->padding();
2020}
2021
2022void QQuickPopup::setPadding(qreal padding)
2023{
2024 Q_D(QQuickPopup);
2025 d->popupItem->setPadding(padding);
2026}
2027
2028void QQuickPopup::resetPadding()
2029{
2030 Q_D(QQuickPopup);
2031 d->popupItem->resetPadding();
2032}
2033
2034/*!
2035 \qmlproperty real QtQuick.Controls::Popup::topPadding
2036
2037 This property holds the top padding. Unless explicitly set, the value
2038 is equal to \c verticalPadding.
2039
2040 \include qquickpopup-padding.qdocinc
2041
2042 \sa padding, bottomPadding, verticalPadding, availableHeight
2043*/
2044qreal QQuickPopup::topPadding() const
2045{
2046 Q_D(const QQuickPopup);
2047 return d->popupItem->topPadding();
2048}
2049
2050void QQuickPopup::setTopPadding(qreal padding)
2051{
2052 Q_D(QQuickPopup);
2053 d->popupItem->setTopPadding(padding);
2054}
2055
2056void QQuickPopup::resetTopPadding()
2057{
2058 Q_D(QQuickPopup);
2059 d->popupItem->resetTopPadding();
2060}
2061
2062/*!
2063 \qmlproperty real QtQuick.Controls::Popup::leftPadding
2064
2065 This property holds the left padding. Unless explicitly set, the value
2066 is equal to \c horizontalPadding.
2067
2068 \include qquickpopup-padding.qdocinc
2069
2070 \sa padding, rightPadding, horizontalPadding, availableWidth
2071*/
2072qreal QQuickPopup::leftPadding() const
2073{
2074 Q_D(const QQuickPopup);
2075 return d->popupItem->leftPadding();
2076}
2077
2078void QQuickPopup::setLeftPadding(qreal padding)
2079{
2080 Q_D(QQuickPopup);
2081 d->popupItem->setLeftPadding(padding);
2082}
2083
2084void QQuickPopup::resetLeftPadding()
2085{
2086 Q_D(QQuickPopup);
2087 d->popupItem->resetLeftPadding();
2088}
2089
2090/*!
2091 \qmlproperty real QtQuick.Controls::Popup::rightPadding
2092
2093 This property holds the right padding. Unless explicitly set, the value
2094 is equal to \c horizontalPadding.
2095
2096 \include qquickpopup-padding.qdocinc
2097
2098 \sa padding, leftPadding, horizontalPadding, availableWidth
2099*/
2100qreal QQuickPopup::rightPadding() const
2101{
2102 Q_D(const QQuickPopup);
2103 return d->popupItem->rightPadding();
2104}
2105
2106void QQuickPopup::setRightPadding(qreal padding)
2107{
2108 Q_D(QQuickPopup);
2109 d->popupItem->setRightPadding(padding);
2110}
2111
2112void QQuickPopup::resetRightPadding()
2113{
2114 Q_D(QQuickPopup);
2115 d->popupItem->resetRightPadding();
2116}
2117
2118/*!
2119 \qmlproperty real QtQuick.Controls::Popup::bottomPadding
2120
2121 This property holds the bottom padding. Unless explicitly set, the value
2122 is equal to \c verticalPadding.
2123
2124 \include qquickpopup-padding.qdocinc
2125
2126 \sa padding, topPadding, verticalPadding, availableHeight
2127*/
2128qreal QQuickPopup::bottomPadding() const
2129{
2130 Q_D(const QQuickPopup);
2131 return d->popupItem->bottomPadding();
2132}
2133
2134void QQuickPopup::setBottomPadding(qreal padding)
2135{
2136 Q_D(QQuickPopup);
2137 d->popupItem->setBottomPadding(padding);
2138}
2139
2140void QQuickPopup::resetBottomPadding()
2141{
2142 Q_D(QQuickPopup);
2143 d->popupItem->resetBottomPadding();
2144}
2145
2146/*!
2147 \qmlproperty Locale QtQuick.Controls::Popup::locale
2148
2149 This property holds the locale of the popup.
2150
2151 \sa mirrored, {LayoutMirroring}{LayoutMirroring}
2152*/
2153QLocale QQuickPopup::locale() const
2154{
2155 Q_D(const QQuickPopup);
2156 return d->popupItem->locale();
2157}
2158
2159void QQuickPopup::setLocale(const QLocale &locale)
2160{
2161 Q_D(QQuickPopup);
2162 d->popupItem->setLocale(locale);
2163}
2164
2165void QQuickPopup::resetLocale()
2166{
2167 Q_D(QQuickPopup);
2168 d->popupItem->resetLocale();
2169}
2170
2171/*!
2172 \since QtQuick.Controls 2.3 (Qt 5.10)
2173 \qmlproperty bool QtQuick.Controls::Popup::mirrored
2174 \readonly
2175
2176 This property holds whether the popup is mirrored.
2177
2178 This property is provided for convenience. A popup is considered mirrored
2179 when its visual layout direction is right-to-left; that is, when using a
2180 right-to-left locale.
2181
2182 \sa locale, {Right-to-left User Interfaces}
2183*/
2184bool QQuickPopup::isMirrored() const
2185{
2186 Q_D(const QQuickPopup);
2187 return d->popupItem->isMirrored();
2188}
2189
2190/*!
2191 \qmlproperty font QtQuick.Controls::Popup::font
2192
2193 This property holds the font currently set for the popup.
2194
2195 Popup propagates explicit font properties to its children. If you change a specific
2196 property on a popup's font, that property propagates to all of the popup's children,
2197 overriding any system defaults for that property.
2198
2199 \code
2200 Popup {
2201 font.family: "Courier"
2202
2203 Column {
2204 Label {
2205 text: qsTr("This will use Courier...")
2206 }
2207
2208 Switch {
2209 text: qsTr("... and so will this")
2210 }
2211 }
2212 }
2213 \endcode
2214
2215 \sa Control::font, ApplicationWindow::font
2216*/
2217QFont QQuickPopup::font() const
2218{
2219 Q_D(const QQuickPopup);
2220 return d->popupItem->font();
2221}
2222
2223void QQuickPopup::setFont(const QFont &font)
2224{
2225 Q_D(QQuickPopup);
2226 d->popupItem->setFont(font);
2227}
2228
2229void QQuickPopup::resetFont()
2230{
2231 Q_D(QQuickPopup);
2232 d->popupItem->resetFont();
2233}
2234
2235QQuickWindow *QQuickPopup::window() const
2236{
2237 Q_D(const QQuickPopup);
2238 return d->window;
2239}
2240
2241QQuickItem *QQuickPopup::popupItem() const
2242{
2243 Q_D(const QQuickPopup);
2244 return d->popupItem;
2245}
2246
2247/*!
2248 \qmlproperty Item QtQuick.Controls::Popup::parent
2249
2250 This property holds the parent item.
2251*/
2252QQuickItem *QQuickPopup::parentItem() const
2253{
2254 Q_D(const QQuickPopup);
2255 return d->parentItem;
2256}
2257
2258void QQuickPopup::setParentItem(QQuickItem *parent)
2259{
2260 Q_D(QQuickPopup);
2261 if (d->parentItem == parent)
2262 return;
2263
2264 if (d->parentItem) {
2265 QObjectPrivate::disconnect(d->parentItem, &QQuickItem::windowChanged, d, &QQuickPopupPrivate::setWindow);
2266 QQuickItemPrivate::get(d->parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Destroyed);
2267 }
2268 d->parentItem = parent;
2269 QQuickPopupPositioner *positioner = d->getPositioner();
2270 if (positioner->parentItem())
2271 positioner->setParentItem(parent);
2272 if (parent) {
2273 QObjectPrivate::connect(parent, &QQuickItem::windowChanged, d, &QQuickPopupPrivate::setWindow);
2274 QQuickItemPrivate::get(d->parentItem)->addItemChangeListener(d, QQuickItemPrivate::Destroyed);
2275 } else if (d->inDestructor) {
2276 d->destroyDimmer();
2277 } else {
2278 // Reset transition manager state when its parent window destroyed
2279 if (!d->window && d->transitionManager.isRunning()) {
2280 if (d->transitionState == QQuickPopupPrivate::EnterTransition)
2281 d->finalizeEnterTransition();
2282 else if (d->transitionState == QQuickPopupPrivate::ExitTransition)
2283 d->finalizeExitTransition();
2284 }
2285 // NOTE: if setParentItem is called from the dtor, this bypasses virtual dispatch and calls
2286 // QQuickPopup::close() directly
2287 close();
2288 }
2289 d->setWindow(parent ? parent->window() : nullptr);
2290 emit parentChanged();
2291}
2292
2293void QQuickPopup::resetParentItem()
2294{
2295 if (QQuickWindow *window = qobject_cast<QQuickWindow *>(parent()))
2296 setParentItem(window->contentItem());
2297 else
2298 setParentItem(findParentItem());
2299}
2300
2301/*!
2302 \qmlproperty Item QtQuick.Controls::Popup::background
2303
2304 This property holds the background item.
2305
2306 \note If the background item has no explicit size specified, it automatically
2307 follows the popup's size. In most cases, there is no need to specify
2308 width or height for a background item.
2309
2310 \note Most popups use the implicit size of the background item to calculate
2311 the implicit size of the popup itself. If you replace the background item
2312 with a custom one, you should also consider providing a sensible implicit
2313 size for it (unless it is an item like \l Image which has its own implicit
2314 size).
2315
2316 \sa {Customizing Popup}
2317*/
2318QQuickItem *QQuickPopup::background() const
2319{
2320 Q_D(const QQuickPopup);
2321 return d->popupItem->background();
2322}
2323
2324void QQuickPopup::setBackground(QQuickItem *background)
2325{
2326 Q_D(QQuickPopup);
2327 // The __notCustomizable property won't be on "this" when the popup item's setBackground function
2328 // is called, so it won't warn. That's why we do a check here.
2329 QQuickControlPrivate::warnIfCustomizationNotSupported(this, background, QStringLiteral("background"));
2330 d->popupItem->setBackground(background);
2331}
2332
2333/*!
2334 \qmlproperty Item QtQuick.Controls::Popup::contentItem
2335
2336 This property holds the content item of the popup.
2337
2338 The content item is the visual implementation of the popup. When the
2339 popup is made visible, the content item is automatically reparented to
2340 the \l {Overlay::overlay}{overlay item}.
2341
2342 \note The content item is automatically resized to fit within the
2343 \l padding of the popup.
2344
2345 \note Most popups use the implicit size of the content item to calculate
2346 the implicit size of the popup itself. If you replace the content item
2347 with a custom one, you should also consider providing a sensible implicit
2348 size for it (unless it is an item like \l Text which has its own implicit
2349 size).
2350
2351 \sa {Customizing Popup}
2352*/
2353QQuickItem *QQuickPopup::contentItem() const
2354{
2355 Q_D(const QQuickPopup);
2356 return d->popupItem->contentItem();
2357}
2358
2359void QQuickPopup::setContentItem(QQuickItem *item)
2360{
2361 Q_D(QQuickPopup);
2362 // See comment in setBackground for why we do this.
2363 QQuickControlPrivate::warnIfCustomizationNotSupported(this, item, QStringLiteral("contentItem"));
2364 QQuickItem *oldContentItem = d->complete ? d->popupItem->d_func()->contentItem.data()
2365 : nullptr;
2366 if (oldContentItem)
2367 disconnect(oldContentItem, &QQuickItem::childrenChanged, this, &QQuickPopup::contentChildrenChanged);
2368 d->popupItem->setContentItem(item);
2369 if (d->complete) {
2370 QQuickItem *newContentItem = d->popupItem->d_func()->contentItem.data();
2371 if (newContentItem)
2372 connect(newContentItem, &QQuickItem::childrenChanged, this, &QQuickPopup::contentChildrenChanged);
2373 if (oldContentItem != newContentItem)
2374 emit contentChildrenChanged();
2375 }
2376}
2377
2378/*!
2379 \qmlproperty list<QtObject> QtQuick.Controls::Popup::contentData
2380 \qmldefault
2381
2382 This property holds the list of content data.
2383
2384 The list contains all objects that have been declared in QML as children
2385 of the popup.
2386
2387 \note Unlike \c contentChildren, \c contentData does include non-visual QML
2388 objects.
2389
2390 \sa Item::data, contentChildren
2391*/
2392QQmlListProperty<QObject> QQuickPopupPrivate::contentData()
2393{
2394 QQuickControlPrivate *p = QQuickControlPrivate::get(popupItem);
2395 if (!p->contentItem)
2396 p->executeContentItem();
2397 return QQmlListProperty<QObject>(popupItem->contentItem(), nullptr,
2398 QQuickItemPrivate::data_append,
2399 QQuickItemPrivate::data_count,
2400 QQuickItemPrivate::data_at,
2401 QQuickItemPrivate::data_clear);
2402}
2403
2404/*!
2405 \qmlproperty list<Item> QtQuick.Controls::Popup::contentChildren
2406
2407 This property holds the list of content children.
2408
2409 The list contains all items that have been declared in QML as children
2410 of the popup.
2411
2412 \note Unlike \c contentData, \c contentChildren does not include non-visual
2413 QML objects.
2414
2415 \sa Item::children, contentData
2416*/
2417QQmlListProperty<QQuickItem> QQuickPopupPrivate::contentChildren()
2418{
2419 return QQmlListProperty<QQuickItem>(popupItem->contentItem(), nullptr,
2420 QQuickItemPrivate::children_append,
2421 QQuickItemPrivate::children_count,
2422 QQuickItemPrivate::children_at,
2423 QQuickItemPrivate::children_clear);
2424}
2425
2426/*!
2427 \qmlproperty bool QtQuick.Controls::Popup::clip
2428
2429 This property holds whether clipping is enabled. The default value is \c false.
2430 Clipping only works when the popup isn't in its own window.
2431*/
2432bool QQuickPopup::clip() const
2433{
2434 Q_D(const QQuickPopup);
2435 return d->popupItem->clip() && !d->usePopupWindow();
2436}
2437
2438void QQuickPopup::setClip(bool clip)
2439{
2440 Q_D(QQuickPopup);
2441 if (clip == d->popupItem->clip() || d->usePopupWindow())
2442 return;
2443 d->popupItem->setClip(clip);
2444 emit clipChanged();
2445}
2446
2447/*!
2448 \qmlproperty bool QtQuick.Controls::Popup::focus
2449
2450 This property holds whether the popup wants focus.
2451
2452 When the popup actually receives focus, \l activeFocus will be \c true.
2453 For more information, see \l {Keyboard Focus in Qt Quick}.
2454
2455 The default value is \c false.
2456
2457 \sa activeFocus
2458*/
2459bool QQuickPopup::hasFocus() const
2460{
2461 Q_D(const QQuickPopup);
2462 return d->focus;
2463}
2464
2465void QQuickPopup::setFocus(bool focus)
2466{
2467 Q_D(QQuickPopup);
2468 if (d->focus == focus)
2469 return;
2470 d->focus = focus;
2471 emit focusChanged();
2472}
2473
2474/*!
2475 \qmlproperty bool QtQuick.Controls::Popup::activeFocus
2476 \readonly
2477
2478 This property holds whether the popup has active focus.
2479
2480 \sa focus, {Keyboard Focus in Qt Quick}
2481*/
2482bool QQuickPopup::hasActiveFocus() const
2483{
2484 Q_D(const QQuickPopup);
2485 return d->popupItem->hasActiveFocus();
2486}
2487
2488/*!
2489 \qmlproperty bool QtQuick.Controls::Popup::modal
2490
2491 This property holds whether the popup is modal.
2492
2493 Modal popups often have a distinctive background dimming effect defined
2494 in \l {Overlay::modal}{Overlay.modal}, and do not allow press
2495 or release events through to items beneath them. For example, if the user
2496 accidentally clicks outside of a popup, any item beneath that popup at
2497 the location of the click will not receive the event.
2498
2499 On desktop platforms, it is common for modal popups to be closed only when
2500 the escape key is pressed. To achieve this behavior, set
2501 \l closePolicy to \c Popup.CloseOnEscape. By default, \c closePolicy
2502 is set to \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}, which
2503 means that clicking outside of a modal popup will close it.
2504
2505 The default value is \c false.
2506
2507 \sa dim
2508*/
2509bool QQuickPopup::isModal() const
2510{
2511 Q_D(const QQuickPopup);
2512 return d->modal;
2513}
2514
2515void QQuickPopup::setModal(bool modal)
2516{
2517 Q_D(QQuickPopup);
2518 if (d->modal == modal)
2519 return;
2520 d->modal = modal;
2521 d->popupWindowDirty = true;
2522 if (d->complete && d->visible)
2523 d->toggleOverlay();
2524 emit modalChanged();
2525
2526 if (!d->hasDim) {
2527 setDim(modal);
2528 d->hasDim = false;
2529 }
2530}
2531
2532/*!
2533 \qmlproperty bool QtQuick.Controls::Popup::dim
2534
2535 This property holds whether the popup dims the background.
2536
2537 Unless explicitly set, this property follows the value of \l modal. To
2538 return to the default value, set this property to \c undefined.
2539
2540 \sa modal, {Overlay::modeless}{Overlay.modeless}
2541*/
2542bool QQuickPopup::dim() const
2543{
2544 Q_D(const QQuickPopup);
2545 return d->dim;
2546}
2547
2548void QQuickPopup::setDim(bool dim)
2549{
2550 Q_D(QQuickPopup);
2551 d->hasDim = true;
2552
2553 if (d->dim == dim)
2554 return;
2555
2556 d->dim = dim;
2557 if (d->complete && d->visible)
2558 d->toggleOverlay();
2559 emit dimChanged();
2560}
2561
2562void QQuickPopup::resetDim()
2563{
2564 Q_D(QQuickPopup);
2565 if (!d->hasDim)
2566 return;
2567
2568 setDim(d->modal);
2569 d->hasDim = false;
2570}
2571
2572/*!
2573 \qmlproperty bool QtQuick.Controls::Popup::visible
2574
2575 This property holds whether the popup is visible. The default value is \c false.
2576
2577 \sa open(), close(), opened
2578*/
2579bool QQuickPopup::isVisible() const
2580{
2581 Q_D(const QQuickPopup);
2582 return d->visible && d->popupItem->isVisible();
2583}
2584
2585void QQuickPopup::setVisible(bool visible)
2586{
2587 Q_D(QQuickPopup);
2588 // During an exit transition, d->visible == true until the transition has completed.
2589 // Therefore, this guard must not return early if setting visible to true while
2590 // d->visible is true.
2591 if (d->visible && visible && d->transitionState != QQuickPopupPrivate::ExitTransition)
2592 return;
2593
2594 if (!d->visible && !visible)
2595 return;
2596
2597 if (!d->complete || (visible && !d->window)) {
2598 d->visible = visible;
2599 return;
2600 }
2601
2602 if (visible && !parentItem()) {
2603 qmlWarning(this) << "cannot show popup: parent is null";
2604 return;
2605 }
2606
2607 if (visible)
2608 openPopup(d);
2609 else
2610 d->transitionManager.transitionExit();
2611}
2612
2613/*!
2614 \since QtQuick.Controls 2.3 (Qt 5.10)
2615 \qmlproperty bool QtQuick.Controls::Popup::enabled
2616
2617 This property holds whether the popup is enabled. The default value is \c true.
2618
2619 \sa visible, Item::enabled
2620*/
2621bool QQuickPopup::isEnabled() const
2622{
2623 Q_D(const QQuickPopup);
2624 return d->popupItem->isEnabled();
2625}
2626
2627void QQuickPopup::setEnabled(bool enabled)
2628{
2629 Q_D(QQuickPopup);
2630 d->popupItem->setEnabled(enabled);
2631}
2632
2633/*!
2634 \since QtQuick.Controls 2.3 (Qt 5.10)
2635 \qmlproperty bool QtQuick.Controls::Popup::opened
2636
2637 This property holds whether the popup is fully open. The popup is considered opened
2638 when it's visible and neither the \l enter nor \l exit transitions are running.
2639
2640 \sa open(), close(), visible
2641*/
2642bool QQuickPopup::isOpened() const
2643{
2644 Q_D(const QQuickPopup);
2645 return d->transitionState == QQuickPopupPrivate::NoTransition && isVisible();
2646}
2647
2648/*!
2649 \qmlproperty real QtQuick.Controls::Popup::opacity
2650
2651 This property holds the opacity of the popup. Opacity is specified as a number between
2652 \c 0.0 (fully transparent) and \c 1.0 (fully opaque). The default value is \c 1.0.
2653
2654 \sa visible
2655*/
2656qreal QQuickPopup::opacity() const
2657{
2658 Q_D(const QQuickPopup);
2659 return d->popupItem->opacity();
2660}
2661
2662void QQuickPopup::setOpacity(qreal opacity)
2663{
2664 Q_D(QQuickPopup);
2665 d->popupItem->setOpacity(opacity);
2666}
2667
2668/*!
2669 \qmlproperty real QtQuick.Controls::Popup::scale
2670
2671 This property holds the scale factor of the popup. The default value is \c 1.0.
2672
2673 A scale of less than \c 1.0 causes the popup to be rendered at a smaller size,
2674 and a scale greater than \c 1.0 renders the popup at a larger size. Negative
2675 scales are not supported.
2676*/
2677qreal QQuickPopup::scale() const
2678{
2679 Q_D(const QQuickPopup);
2680 return d->popupItem->scale();
2681}
2682
2683void QQuickPopup::setScale(qreal scale)
2684{
2685 Q_D(QQuickPopup);
2686 if (qFuzzyCompare(scale, d->popupItem->scale()))
2687 return;
2688 d->popupItem->setScale(scale);
2689 emit scaleChanged();
2690}
2691
2692/*!
2693 \qmlproperty enumeration QtQuick.Controls::Popup::closePolicy
2694
2695 This property determines the circumstances under which the popup closes.
2696 The flags can be combined to allow several ways of closing the popup.
2697
2698 The available values are:
2699 \value Popup.NoAutoClose The popup will only close when manually instructed to do so.
2700 \value Popup.CloseOnPressOutside The popup will close when the mouse is pressed outside of it.
2701 \value Popup.CloseOnPressOutsideParent The popup will close when the mouse is pressed outside of its parent.
2702 \value Popup.CloseOnReleaseOutside The popup will close when the mouse is released outside of it.
2703 \value Popup.CloseOnReleaseOutsideParent The popup will close when the mouse is released outside of its parent.
2704 \value Popup.CloseOnEscape The popup will close when the escape key is pressed while the popup
2705 has active focus.
2706
2707 The \c {CloseOnPress*} and \c {CloseOnRelease*} policies only apply for events
2708 outside of popups. That is, if there are two popups open and the first has
2709 \c Popup.CloseOnPressOutside as its policy, clicking on the second popup will
2710 not result in the first closing.
2711
2712 The default value is \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}.
2713
2714 \note There is a known limitation that the \c Popup.CloseOnReleaseOutside
2715 and \c Popup.CloseOnReleaseOutsideParent policies only work with
2716 \l modal popups.
2717*/
2718QQuickPopup::ClosePolicy QQuickPopup::closePolicy() const
2719{
2720 Q_D(const QQuickPopup);
2721 return d->closePolicy;
2722}
2723
2724void QQuickPopup::setClosePolicy(ClosePolicy policy)
2725{
2726 Q_D(QQuickPopup);
2727 d->hasClosePolicy = true;
2728 if (d->closePolicy == policy)
2729 return;
2730 d->closePolicy = policy;
2731 emit closePolicyChanged();
2732}
2733
2734void QQuickPopup::resetClosePolicy()
2735{
2736 Q_D(QQuickPopup);
2737 setClosePolicy(QQuickPopupPrivate::DefaultClosePolicy);
2738 d->hasClosePolicy = false;
2739}
2740
2741/*!
2742 \qmlproperty enumeration QtQuick.Controls::Popup::transformOrigin
2743
2744 This property holds the origin point for transformations in enter and exit transitions.
2745
2746 Nine transform origins are available, as shown in the image below.
2747 The default transform origin is \c Popup.Center.
2748
2749 \image qtquickcontrols-popup-transformorigin.png
2750 {Popup demonstrating transform origin points}
2751
2752 \sa enter, exit, Item::transformOrigin
2753*/
2754QQuickPopup::TransformOrigin QQuickPopup::transformOrigin() const
2755{
2756 Q_D(const QQuickPopup);
2757 return static_cast<TransformOrigin>(d->popupItem->transformOrigin());
2758}
2759
2760void QQuickPopup::setTransformOrigin(TransformOrigin origin)
2761{
2762 Q_D(QQuickPopup);
2763 d->popupItem->setTransformOrigin(static_cast<QQuickItem::TransformOrigin>(origin));
2764}
2765
2766/*!
2767 \qmlproperty Transition QtQuick.Controls::Popup::enter
2768
2769 This property holds the transition that is applied to the popup item
2770 when the popup is opened and enters the screen.
2771
2772 The following example animates the opacity of the popup when it enters
2773 the screen:
2774 \code
2775 Popup {
2776 enter: Transition {
2777 NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 }
2778 }
2779 }
2780 \endcode
2781
2782 \sa exit
2783*/
2784QQuickTransition *QQuickPopup::enter() const
2785{
2786 Q_D(const QQuickPopup);
2787 return d->enter;
2788}
2789
2790void QQuickPopup::setEnter(QQuickTransition *transition)
2791{
2792 Q_D(QQuickPopup);
2793 if (d->enter == transition)
2794 return;
2795 d->enter = transition;
2796 emit enterChanged();
2797}
2798
2799/*!
2800 \qmlproperty Transition QtQuick.Controls::Popup::exit
2801
2802 This property holds the transition that is applied to the popup item
2803 when the popup is closed and exits the screen.
2804
2805 The following example animates the opacity of the popup when it exits
2806 the screen:
2807 \code
2808 Popup {
2809 exit: Transition {
2810 NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 }
2811 }
2812 }
2813 \endcode
2814
2815 \sa enter
2816*/
2817QQuickTransition *QQuickPopup::exit() const
2818{
2819 Q_D(const QQuickPopup);
2820 return d->exit;
2821}
2822
2823void QQuickPopup::setExit(QQuickTransition *transition)
2824{
2825 Q_D(QQuickPopup);
2826 if (d->exit == transition)
2827 return;
2828 d->exit = transition;
2829 emit exitChanged();
2830}
2831
2832/*!
2833 \since QtQuick.Controls 2.5 (Qt 5.12)
2834 \qmlproperty real QtQuick.Controls::Popup::horizontalPadding
2835
2836 This property holds the horizontal padding. Unless explicitly set, the value
2837 is equal to \c padding.
2838
2839 \include qquickpopup-padding.qdocinc
2840
2841 \sa padding, leftPadding, rightPadding, verticalPadding
2842*/
2843qreal QQuickPopup::horizontalPadding() const
2844{
2845 Q_D(const QQuickPopup);
2846 return d->popupItem->horizontalPadding();
2847}
2848
2849void QQuickPopup::setHorizontalPadding(qreal padding)
2850{
2851 Q_D(QQuickPopup);
2852 d->popupItem->setHorizontalPadding(padding);
2853}
2854
2855void QQuickPopup::resetHorizontalPadding()
2856{
2857 Q_D(QQuickPopup);
2858 d->popupItem->resetHorizontalPadding();
2859}
2860
2861/*!
2862 \since QtQuick.Controls 2.5 (Qt 5.12)
2863 \qmlproperty real QtQuick.Controls::Popup::verticalPadding
2864
2865 This property holds the vertical padding. Unless explicitly set, the value
2866 is equal to \c padding.
2867
2868 \include qquickpopup-padding.qdocinc
2869
2870 \sa padding, topPadding, bottomPadding, horizontalPadding
2871*/
2872qreal QQuickPopup::verticalPadding() const
2873{
2874 Q_D(const QQuickPopup);
2875 return d->popupItem->verticalPadding();
2876}
2877
2878void QQuickPopup::setVerticalPadding(qreal padding)
2879{
2880 Q_D(QQuickPopup);
2881 d->popupItem->setVerticalPadding(padding);
2882}
2883
2884void QQuickPopup::resetVerticalPadding()
2885{
2886 Q_D(QQuickPopup);
2887 d->popupItem->resetVerticalPadding();
2888}
2889
2890/*!
2891 \since QtQuick.Controls 2.5 (Qt 5.12)
2892 \qmlproperty real QtQuick.Controls::Popup::implicitContentWidth
2893 \readonly
2894
2895 This property holds the implicit content width.
2896
2897 The value is calculated based on the content children.
2898
2899 \sa implicitContentHeight, implicitBackgroundWidth
2900*/
2901qreal QQuickPopup::implicitContentWidth() const
2902{
2903 Q_D(const QQuickPopup);
2904 return d->popupItem->implicitContentWidth();
2905}
2906
2907/*!
2908 \since QtQuick.Controls 2.5 (Qt 5.12)
2909 \qmlproperty real QtQuick.Controls::Popup::implicitContentHeight
2910 \readonly
2911
2912 This property holds the implicit content height.
2913
2914 The value is calculated based on the content children.
2915
2916 \sa implicitContentWidth, implicitBackgroundHeight
2917*/
2918qreal QQuickPopup::implicitContentHeight() const
2919{
2920 Q_D(const QQuickPopup);
2921 return d->popupItem->implicitContentHeight();
2922}
2923
2924/*!
2925 \since QtQuick.Controls 2.5 (Qt 5.12)
2926 \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundWidth
2927 \readonly
2928
2929 This property holds the implicit background width.
2930
2931 The value is equal to \c {background ? background.implicitWidth : 0}.
2932
2933 \sa implicitBackgroundHeight, implicitContentWidth
2934*/
2935qreal QQuickPopup::implicitBackgroundWidth() const
2936{
2937 Q_D(const QQuickPopup);
2938 return d->popupItem->implicitBackgroundWidth();
2939}
2940
2941/*!
2942 \since QtQuick.Controls 2.5 (Qt 5.12)
2943 \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundHeight
2944 \readonly
2945
2946 This property holds the implicit background height.
2947
2948 The value is equal to \c {background ? background.implicitHeight : 0}.
2949
2950 \sa implicitBackgroundWidth, implicitContentHeight
2951*/
2952qreal QQuickPopup::implicitBackgroundHeight() const
2953{
2954 Q_D(const QQuickPopup);
2955 return d->popupItem->implicitBackgroundHeight();
2956}
2957
2958/*!
2959 \since QtQuick.Controls 2.5 (Qt 5.12)
2960 \qmlproperty real QtQuick.Controls::Popup::topInset
2961
2962 This property holds the top inset for the background.
2963
2964 \sa {Popup Layout}, bottomInset
2965*/
2966qreal QQuickPopup::topInset() const
2967{
2968 Q_D(const QQuickPopup);
2969 return d->popupItem->topInset();
2970}
2971
2972void QQuickPopup::setTopInset(qreal inset)
2973{
2974 Q_D(QQuickPopup);
2975 d->popupItem->setTopInset(inset);
2976}
2977
2978void QQuickPopup::resetTopInset()
2979{
2980 Q_D(QQuickPopup);
2981 d->popupItem->resetTopInset();
2982}
2983
2984/*!
2985 \since QtQuick.Controls 2.5 (Qt 5.12)
2986 \qmlproperty real QtQuick.Controls::Popup::leftInset
2987
2988 This property holds the left inset for the background.
2989
2990 \sa {Popup Layout}, rightInset
2991*/
2992qreal QQuickPopup::leftInset() const
2993{
2994 Q_D(const QQuickPopup);
2995 return d->popupItem->leftInset();
2996}
2997
2998void QQuickPopup::setLeftInset(qreal inset)
2999{
3000 Q_D(QQuickPopup);
3001 d->popupItem->setLeftInset(inset);
3002}
3003
3004void QQuickPopup::resetLeftInset()
3005{
3006 Q_D(QQuickPopup);
3007 d->popupItem->resetLeftInset();
3008}
3009
3010/*!
3011 \since QtQuick.Controls 2.5 (Qt 5.12)
3012 \qmlproperty real QtQuick.Controls::Popup::rightInset
3013
3014 This property holds the right inset for the background.
3015
3016 \sa {Popup Layout}, leftInset
3017*/
3018qreal QQuickPopup::rightInset() const
3019{
3020 Q_D(const QQuickPopup);
3021 return d->popupItem->rightInset();
3022}
3023
3024void QQuickPopup::setRightInset(qreal inset)
3025{
3026 Q_D(QQuickPopup);
3027 d->popupItem->setRightInset(inset);
3028}
3029
3030void QQuickPopup::resetRightInset()
3031{
3032 Q_D(QQuickPopup);
3033 d->popupItem->resetRightInset();
3034}
3035
3036/*!
3037 \since QtQuick.Controls 2.5 (Qt 5.12)
3038 \qmlproperty real QtQuick.Controls::Popup::bottomInset
3039
3040 This property holds the bottom inset for the background.
3041
3042 \sa {Popup Layout}, topInset
3043*/
3044qreal QQuickPopup::bottomInset() const
3045{
3046 Q_D(const QQuickPopup);
3047 return d->popupItem->bottomInset();
3048}
3049
3050void QQuickPopup::setBottomInset(qreal inset)
3051{
3052 Q_D(QQuickPopup);
3053 d->popupItem->setBottomInset(inset);
3054}
3055
3056void QQuickPopup::resetBottomInset()
3057{
3058 Q_D(QQuickPopup);
3059 d->popupItem->resetBottomInset();
3060}
3061
3062
3063/*!
3064 \qmlproperty enumeration QtQuick.Controls::Popup::popupType
3065 \since 6.8
3066
3067 This property determines the type of popup that is preferred.
3068
3069 Available options:
3070 \value Item The popup will be embedded into the
3071 \l{Showing a popup as an item}{same scene as the parent},
3072 without the use of a separate window.
3073 \value Window The popup will be presented in a \l {Popup type}
3074 {separate window}. If the platform doesn't support
3075 multiple windows, \c Popup.Item will be used instead.
3076 \value Native The popup will be native to the platform. If the
3077 platform doesn't support native popups, \c Popup.Window
3078 will be used instead.
3079
3080 Whether a popup will be able to use the preferred type depends on the platform.
3081 \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
3082 are normally only supported on desktop platforms. Additionally, if a popup is a
3083 \l Menu inside a \l {Native menu bars}{native menubar}, the menu will be native as
3084 well. And if the menu is a sub-menu inside another menu, the parent (or root) menu
3085 will decide the type.
3086
3087 The default value is usually \c Popup.Item, with some exceptions, mentioned above.
3088 This might change in future versions of Qt, for certain styles and platforms that benefit
3089 from using other popup types.
3090 If you always want to use native menus for all styles on macOS, for example, you can do:
3091
3092 \code
3093 Menu {
3094 popupType: Qt.platform.os === "osx" ? Popup.Native : Popup.Window
3095 }
3096 \endcode
3097
3098 Also, if you choose to customize a popup (by for example changing any of the
3099 delegates), you should consider setting the popup type to be \c Popup.Window
3100 as well. This will ensure that your changes will be visible on all platforms
3101 and for all styles. Otherwise, when native menus are being used, the delegates
3102 will \e not be used for rendering.
3103
3104 \sa {Popup type}
3105*/
3106QQuickPopup::PopupType QQuickPopup::popupType() const
3107{
3108 Q_D(const QQuickPopup);
3109 return d->popupType;
3110}
3111
3112void QQuickPopup::setPopupType(PopupType popupType)
3113{
3114 Q_D(QQuickPopup);
3115 if (d->popupType == popupType)
3116 return;
3117
3118 d->popupType = popupType;
3119
3120 emit popupTypeChanged();
3121}
3122
3123/*!
3124 \since QtQuick.Controls 2.3 (Qt 5.10)
3125 \qmlproperty palette QtQuick.Controls::Popup::palette
3126
3127 This property holds the palette currently set for the popup.
3128
3129 Popup propagates explicit palette properties to its children. If you change a specific
3130 property on a popup's palette, that property propagates to all of the popup's children,
3131 overriding any system defaults for that property.
3132
3133 \code
3134 Popup {
3135 palette.text: "red"
3136
3137 Column {
3138 Label {
3139 text: qsTr("This will use red color...")
3140 }
3141
3142 Switch {
3143 text: qsTr("... and so will this")
3144 }
3145 }
3146 }
3147 \endcode
3148
3149 \b {See also}: \l Item::palette, \l Window::palette, \l ColorGroup,
3150 \l [QML] {Palette}
3151*/
3152
3153bool QQuickPopup::filtersChildMouseEvents() const
3154{
3155 Q_D(const QQuickPopup);
3156 return d->popupItem->filtersChildMouseEvents();
3157}
3158
3159void QQuickPopup::setFiltersChildMouseEvents(bool filter)
3160{
3161 Q_D(QQuickPopup);
3162 d->popupItem->setFiltersChildMouseEvents(filter);
3163}
3164
3165/*!
3166 \qmlmethod void QtQuick.Controls::Popup::forceActiveFocus(enumeration reason = Qt.OtherFocusReason)
3167
3168 Forces active focus on the popup with the given \a reason.
3169
3170 This method sets focus on the popup and ensures that all ancestor
3171 \l FocusScope objects in the object hierarchy are also given \l focus.
3172
3173 \sa activeFocus, Qt::FocusReason
3174*/
3175void QQuickPopup::forceActiveFocus(Qt::FocusReason reason)
3176{
3177 Q_D(QQuickPopup);
3178 d->popupItem->forceActiveFocus(reason);
3179}
3180
3181void QQuickPopup::classBegin()
3182{
3183 Q_D(QQuickPopup);
3184 d->complete = false;
3185 QQmlContext *context = qmlContext(this);
3186 if (context)
3187 QQmlEngine::setContextForObject(d->popupItem, context);
3188 d->popupItem->classBegin();
3189}
3190
3191void QQuickPopup::componentComplete()
3192{
3193 Q_D(QQuickPopup);
3194 qCDebug(lcQuickPopup) << "componentComplete" << this;
3195 if (!parentItem())
3196 resetParentItem();
3197
3198 d->complete = true;
3199 d->popupItem->setObjectName(QQmlMetaType::prettyTypeName(this));
3200 d->popupItem->componentComplete();
3201
3202 if (auto currentContentItem = d->popupItem->d_func()->contentItem.data()) {
3203 connect(currentContentItem, &QQuickItem::childrenChanged,
3204 this, &QQuickPopup::contentChildrenChanged);
3205 }
3206
3207 if (d->visible && d->window)
3208 openPopup(d);
3209}
3210
3211bool QQuickPopup::isComponentComplete() const
3212{
3213 Q_D(const QQuickPopup);
3214 return d->complete;
3215}
3216
3217bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event)
3218{
3219 Q_UNUSED(child);
3220 Q_UNUSED(event);
3221 return false;
3222}
3223
3224void QQuickPopup::focusInEvent(QFocusEvent *event)
3225{
3226 event->accept();
3227}
3228
3229void QQuickPopup::focusOutEvent(QFocusEvent *event)
3230{
3231 event->accept();
3232}
3233
3234void QQuickPopup::keyPressEvent(QKeyEvent *event)
3235{
3236 Q_D(QQuickPopup);
3237 if (!hasActiveFocus())
3238 return;
3239
3240#if QT_CONFIG(shortcut)
3241 if (d->closePolicy.testFlag(QQuickPopup::CloseOnEscape)
3242 && (event->matches(QKeySequence::Cancel)
3243#if defined(Q_OS_ANDROID)
3244 || event->key() == Qt::Key_Back
3245#endif
3246 )) {
3247 event->accept();
3248 if (d->interactive)
3249 d->closeOrReject();
3250 return;
3251 }
3252#endif
3253
3254 if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)) {
3255 event->accept();
3256 QQuickItemPrivate::focusNextPrev(d->popupItem, event->key() == Qt::Key_Tab);
3257 }
3258}
3259
3260void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
3261{
3262 event->accept();
3263}
3264
3265void QQuickPopup::mousePressEvent(QMouseEvent *event)
3266{
3267 Q_D(QQuickPopup);
3268 event->setAccepted(d->handleMouseEvent(d->popupItem, event));
3269}
3270
3271void QQuickPopup::mouseMoveEvent(QMouseEvent *event)
3272{
3273 Q_D(QQuickPopup);
3274 event->setAccepted(d->handleMouseEvent(d->popupItem, event));
3275}
3276
3277void QQuickPopup::mouseReleaseEvent(QMouseEvent *event)
3278{
3279 Q_D(QQuickPopup);
3280 event->setAccepted(d->handleMouseEvent(d->popupItem, event));
3281}
3282
3283void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event)
3284{
3285 event->accept();
3286}
3287
3288void QQuickPopup::mouseUngrabEvent()
3289{
3290 Q_D(QQuickPopup);
3291 d->handleUngrab();
3292}
3293
3294
3295static QQuickItem *findRootOfOverlaySubtree(QQuickItem *source, const QQuickOverlay *overlay)
3296{
3297 QQuickItem *sourceAncestor = source;
3298 while (sourceAncestor) {
3299 QQuickItem *parentItem = sourceAncestor->parentItem();
3300 if (parentItem == overlay)
3301 return sourceAncestor;
3302 sourceAncestor = parentItem;
3303 }
3304 // Not an ancestor of the overlay.
3305 return nullptr;
3306}
3307
3308/*!
3309 \internal
3310
3311 Called whenever the window receives a Wheel/Hover/Mouse/Touch/Tablet event,
3312 and has an active popup (with popupType: Popup.Item) in its scene.
3313
3314 The purpose is to close popups when the press/release event happened outside of it,
3315 and the closePolicy allows for it to happen.
3316
3317 If the function is called from childMouseEventFilter, then the return value of this
3318 function will determine whether the event will be filtered, or delivered to \a item.
3319*/
3320bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event)
3321{
3322 Q_D(QQuickPopup);
3323
3324 // The overlay will normally call this function for each active popup, assuming there is no active mouse grabber.
3325 // If \a item doesn't belong to any of these popups, but exists in an overlay subtree, we shouldn't filter the event,
3326 // since the item is supposed to be independent of any active popups.
3327 auto *overlay = QQuickOverlay::overlay(d->window, d->parentItem);
3328 Q_ASSERT(overlay);
3329 const QList<QQuickItem *> paintOrderChildItems = QQuickOverlayPrivate::get(overlay)->paintOrderChildItems();
3330 const qsizetype targetItemPaintOrderIndex = paintOrderChildItems.indexOf(findRootOfOverlaySubtree(item, overlay));
3331 const qsizetype popupItemPaintOrderIndex = paintOrderChildItems.indexOf(d->popupItem);
3332 if (targetItemPaintOrderIndex > popupItemPaintOrderIndex)
3333 return false;
3334
3335 switch (event->type()) {
3336 case QEvent::KeyPress:
3337 case QEvent::KeyRelease:
3338 case QEvent::MouseMove:
3339 case QEvent::Wheel:
3340 if (d->modal)
3341 event->accept();
3342 return d->modal;
3343 case QEvent::DragEnter:
3344 case QEvent::DragMove:
3345 case QEvent::DragLeave:
3346 case QEvent::Drop:
3347 // ignore() so that the OS sees Qt::IgnoreAction and renders the "not allowed" cursor
3348 // within the drag image. accept() would only change the window cursor after the drag ends: too late.
3349 if (d->modal)
3350 event->ignore();
3351 return d->modal;
3352#if QT_CONFIG(tabletevent)
3353 case QEvent::TabletPress:
3354 case QEvent::TabletMove:
3355 case QEvent::TabletRelease:
3356 if (d->modal)
3357 event->accept();
3358 return d->modal;
3359#endif
3360#if QT_CONFIG(quicktemplates2_multitouch)
3361 case QEvent::TouchBegin:
3362 case QEvent::TouchUpdate:
3363 case QEvent::TouchEnd:
3364 return d->handleTouchEvent(item, static_cast<QTouchEvent *>(event));
3365#endif
3366 case QEvent::HoverEnter:
3367 case QEvent::HoverMove:
3368 case QEvent::HoverLeave:
3369 return d->handleHoverEvent(item, static_cast<QHoverEvent *>(event));
3370
3371 case QEvent::MouseButtonPress:
3372 case QEvent::MouseButtonRelease:
3373 return d->handleMouseEvent(item, static_cast<QMouseEvent *>(event));
3374
3375 default:
3376 return false;
3377 }
3378}
3379
3380#if QT_CONFIG(quicktemplates2_multitouch)
3381void QQuickPopup::touchEvent(QTouchEvent *event)
3382{
3383 Q_D(QQuickPopup);
3384 event->setAccepted(d->handleTouchEvent(d->popupItem, event));
3385}
3386
3387void QQuickPopup::touchUngrabEvent()
3388{
3389 Q_D(QQuickPopup);
3390 d->handleUngrab();
3391}
3392#endif
3393
3394#if QT_CONFIG(wheelevent)
3395void QQuickPopup::wheelEvent(QWheelEvent *event)
3396{
3397 event->accept();
3398}
3399#endif
3400
3401#if QT_CONFIG(quick_draganddrop)
3402void QQuickPopup::dragMoveEvent(QDragMoveEvent *event)
3403{
3404 event->accept();
3405}
3406
3407void QQuickPopup::dragLeaveEvent(QDragLeaveEvent *event)
3408{
3409 event->accept();
3410}
3411
3412void QQuickPopup::dropEvent(QDropEvent *event)
3413{
3414 event->accept();
3415}
3416
3417void QQuickPopup::dragEnterEvent(QDragEnterEvent *event)
3418{
3419 event->ignore(); // OS shows "forbidden" cursor as part of drag image
3420}
3421#endif
3422
3423void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
3424{
3425 Q_UNUSED(newItem);
3426 Q_UNUSED(oldItem);
3427}
3428
3429void QQuickPopup::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
3430{
3431 qCDebug(lcQuickPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
3432 if (!qFuzzyCompare(newSize.width(), oldSize.width()))
3433 emit contentWidthChanged();
3434 if (!qFuzzyCompare(newSize.height(), oldSize.height()))
3435 emit contentHeightChanged();
3436}
3437
3438void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont)
3439{
3440 Q_UNUSED(newFont);
3441 Q_UNUSED(oldFont);
3442 emit fontChanged();
3443}
3444
3445void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
3446{
3447 Q_D(QQuickPopup);
3448 qCDebug(lcQuickPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
3449 if (!d->usePopupWindow())
3450 d->reposition();
3451 if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) {
3452 emit widthChanged();
3453 emit availableWidthChanged();
3454 }
3455 if (!qFuzzyCompare(newGeometry.height(), oldGeometry.height())) {
3456 emit heightChanged();
3457 emit availableHeightChanged();
3458 }
3459}
3460
3461void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &)
3462{
3463 switch (change) {
3464 case QQuickItem::ItemActiveFocusHasChanged:
3465 emit activeFocusChanged();
3466 break;
3467 case QQuickItem::ItemOpacityHasChanged:
3468 emit opacityChanged();
3469 break;
3470 default:
3471 break;
3472 }
3473}
3474
3475void QQuickPopup::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
3476{
3477 Q_UNUSED(newLocale);
3478 Q_UNUSED(oldLocale);
3479 emit localeChanged();
3480}
3481
3482void QQuickPopup::marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins)
3483{
3484 Q_D(QQuickPopup);
3485 Q_UNUSED(newMargins);
3486 Q_UNUSED(oldMargins);
3487 d->reposition();
3488}
3489
3490void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
3491{
3492 const bool tp = !qFuzzyCompare(newPadding.top(), oldPadding.top());
3493 const bool lp = !qFuzzyCompare(newPadding.left(), oldPadding.left());
3494 const bool rp = !qFuzzyCompare(newPadding.right(), oldPadding.right());
3495 const bool bp = !qFuzzyCompare(newPadding.bottom(), oldPadding.bottom());
3496
3497 if (tp)
3498 emit topPaddingChanged();
3499 if (lp)
3500 emit leftPaddingChanged();
3501 if (rp)
3502 emit rightPaddingChanged();
3503 if (bp)
3504 emit bottomPaddingChanged();
3505
3506 if (lp || rp) {
3507 emit horizontalPaddingChanged();
3508 emit availableWidthChanged();
3509 }
3510 if (tp || bp) {
3511 emit verticalPaddingChanged();
3512 emit availableHeightChanged();
3513 }
3514}
3515
3516void QQuickPopup::spacingChange(qreal newSpacing, qreal oldSpacing)
3517{
3518 Q_UNUSED(newSpacing);
3519 Q_UNUSED(oldSpacing);
3520 emit spacingChanged();
3521}
3522
3523void QQuickPopup::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
3524{
3525 if (!qFuzzyCompare(newInset.top(), oldInset.top()))
3526 emit topInsetChanged();
3527 if (!qFuzzyCompare(newInset.left(), oldInset.left()))
3528 emit leftInsetChanged();
3529 if (!qFuzzyCompare(newInset.right(), oldInset.right()))
3530 emit rightInsetChanged();
3531 if (!qFuzzyCompare(newInset.bottom(), oldInset.bottom()))
3532 emit bottomInsetChanged();
3533}
3534
3535QFont QQuickPopup::defaultFont() const
3536{
3537 return QQuickTheme::font(QQuickTheme::System);
3538}
3539
3540#if QT_CONFIG(accessibility)
3541QAccessible::Role QQuickPopup::effectiveAccessibleRole() const
3542{
3543 auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, false);
3544
3545 auto role = QAccessible::NoRole;
3546 if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(attached))
3547 role = accessibleAttached->role();
3548 if (role == QAccessible::NoRole)
3549 role = accessibleRole();
3550
3551 return role;
3552}
3553
3554QAccessible::Role QQuickPopup::accessibleRole() const
3555{
3556 return QAccessible::Dialog;
3557}
3558
3559void QQuickPopup::accessibilityActiveChanged(bool active)
3560{
3561 Q_UNUSED(active);
3562}
3563#endif
3564
3565QString QQuickPopup::accessibleName() const
3566{
3567 Q_D(const QQuickPopup);
3568 return d->popupItem->accessibleName();
3569}
3570
3571void QQuickPopup::maybeSetAccessibleName(const QString &name)
3572{
3573 Q_D(QQuickPopup);
3574 d->popupItem->maybeSetAccessibleName(name);
3575}
3576
3577QVariant QQuickPopup::accessibleProperty(const char *propertyName)
3578{
3579 Q_D(const QQuickPopup);
3580 return d->popupItem->accessibleProperty(propertyName);
3581}
3582
3583bool QQuickPopup::setAccessibleProperty(const char *propertyName, const QVariant &value)
3584{
3585 Q_D(QQuickPopup);
3586 return d->popupItem->setAccessibleProperty(propertyName, value);
3587}
3588
3589void QQuickPopup::setWindowModality(const Qt::WindowModality modality)
3590{
3591 Q_D(QQuickPopup);
3592 d->popupWndModality = modality;
3593}
3594
3595QQuickItem *QQuickPopup::safeAreaAttachmentItem()
3596{
3597 return popupItem();
3598}
3599
3600QQuickItem *QQuickPopup::attacheeItem() const
3601{
3602 return popupItem();
3603}
3604
3605QtPrivate::QQuickAttachedPropertyPropagator *QQuickPopup::attachedParent(
3606 const QMetaObject *ourAttachedType) const
3607{
3608 auto *popupWindow = popupItem()->window();
3609 qCDebug(lcAttachedPropertyPropagator).noquote() << "- attachee is a popup; checking its window"
3610 << popupWindow;
3611 auto *object = QtPrivate::QQuickAttachedPropertyPropagator::attachedObject(
3612 ourAttachedType, popupWindow);
3613 if (object)
3614 return object;
3615
3616 if (qobject_cast<QQuickPopupWindow *>(popupWindow)) {
3617 qCDebug(lcAttachedPropertyPropagator).noquote() << "- checking its window's transientParent"
3618 << popupWindow->transientParent();
3619 return QtPrivate::QQuickAttachedPropertyPropagator::attachedObject(ourAttachedType,
3620 popupWindow->transientParent());
3621 }
3622
3623 return {};
3624}
3625
3626QT_END_NAMESPACE
3627
3628#include "qquickpopup.moc"
3629#include "moc_qquickpopup_p.cpp"
Combined button and popup list for selecting options.
static std::unique_ptr< QWindowExposedObserver, ObserverDeleter > s_windowExposedObserver
static QQuickItem * findRootOfOverlaySubtree(QQuickItem *source, const QQuickOverlay *overlay)
void openPopup(QQuickPopupPrivate *d)
void operator()(QWindowExposedObserver *observer)