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