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