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