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

source code of qtdeclarative/src/quicktemplates/qquickpopup.cpp