diff options
author | J-P Nurmi <jpnurmi@theqtcompany.com> | 2016-01-25 11:02:44 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@theqtcompany.com> | 2016-01-25 11:03:53 +0100 |
commit | 5ada1525e03116326a480fb05611904d3484c296 (patch) | |
tree | f23822e6b0482012065b9586d95cb8ab5d70c4bf /src/templates | |
parent | f4f5e857447d42738b1b60b5c4184f39df2f1593 (diff) | |
parent | 4f1fb09ed70c69e73f2e19f28f4299f4cfbc90dc (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
.gitignore
src/templates/qquickcombobox_p.h
src/templates/qquickmenu_p.h
src/templates/qquickmenu_p_p.h
src/templates/qquickoverlay_p.h
src/templates/qquickpopup.cpp
src/templates/qquickpopup_p.h
src/templates/qquickstackview_p.cpp
Change-Id: I89c7d518697beec0b81ef3a12205286a4f3ccf89
Diffstat (limited to 'src/templates')
45 files changed, 1364 insertions, 74 deletions
diff --git a/src/templates/qquickabstractbutton.cpp b/src/templates/qquickabstractbutton.cpp index 5fde4be1..6c42d7d8 100644 --- a/src/templates/qquickabstractbutton.cpp +++ b/src/templates/qquickabstractbutton.cpp @@ -62,6 +62,8 @@ static const int AUTO_REPEAT_INTERVAL = 100; implementations, leaving them to the types that derive from it. TODO: ButtonGroup usage + + \labs */ /*! diff --git a/src/templates/qquickapplicationwindow.cpp b/src/templates/qquickapplicationwindow.cpp index b49f80af..80e347c9 100644 --- a/src/templates/qquickapplicationwindow.cpp +++ b/src/templates/qquickapplicationwindow.cpp @@ -81,6 +81,8 @@ QT_BEGIN_NAMESPACE \note By default, an ApplicationWindow is not visible. + \labs + \sa Page, {Container Controls} */ diff --git a/src/templates/qquickbusyindicator.cpp b/src/templates/qquickbusyindicator.cpp index 8751ef7c..381ac5c7 100644 --- a/src/templates/qquickbusyindicator.cpp +++ b/src/templates/qquickbusyindicator.cpp @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE } \endqml + \labs + \sa {Customizing BusyIndicator}, {Indicator Controls} */ diff --git a/src/templates/qquickbutton.cpp b/src/templates/qquickbutton.cpp index b323cb0b..1e40ec05 100644 --- a/src/templates/qquickbutton.cpp +++ b/src/templates/qquickbutton.cpp @@ -80,6 +80,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing Button}, {Button Controls} */ diff --git a/src/templates/qquickbuttongroup.cpp b/src/templates/qquickbuttongroup.cpp index af975cad..c1822183 100644 --- a/src/templates/qquickbuttongroup.cpp +++ b/src/templates/qquickbuttongroup.cpp @@ -119,6 +119,8 @@ QT_BEGIN_NAMESPACE More advanced use cases can be handled using the addButton() and removeButton() methods. + \labs + \sa RadioButton */ diff --git a/src/templates/qquickcheckbox.cpp b/src/templates/qquickcheckbox.cpp index 9a416419..644e151e 100644 --- a/src/templates/qquickcheckbox.cpp +++ b/src/templates/qquickcheckbox.cpp @@ -80,6 +80,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing CheckBox}, {Button Controls} */ diff --git a/src/templates/qquickcombobox.cpp b/src/templates/qquickcombobox.cpp index 9bf1c4e6..3283a46e 100644 --- a/src/templates/qquickcombobox.cpp +++ b/src/templates/qquickcombobox.cpp @@ -98,6 +98,8 @@ QT_BEGIN_NAMESPACE \l textRole is not defined, ComboBox is unable to visualize it and throws a \c {ReferenceError: modelData is not defined}. + \labs + \sa {Customizing ComboBox}, {Input Controls} */ @@ -330,6 +332,13 @@ QQuickComboBox::QQuickComboBox(QQuickItem *parent) : setAcceptedMouseButtons(Qt::LeftButton); } +QQuickComboBox::~QQuickComboBox() +{ + Q_D(QQuickComboBox); + delete d->popup; + d->popup = nullptr; +} + /*! \readonly \qmlproperty int Qt.labs.controls::ComboBox::count diff --git a/src/templates/qquickcombobox_p.h b/src/templates/qquickcombobox_p.h index 30bc7760..3381791e 100644 --- a/src/templates/qquickcombobox_p.h +++ b/src/templates/qquickcombobox_p.h @@ -73,6 +73,7 @@ class Q_LABSTEMPLATES_EXPORT QQuickComboBox : public QQuickControl public: explicit QQuickComboBox(QQuickItem *parent = nullptr); + ~QQuickComboBox(); int count() const; diff --git a/src/templates/qquickcontainer.cpp b/src/templates/qquickcontainer.cpp index c6638768..d5c387fb 100644 --- a/src/templates/qquickcontainer.cpp +++ b/src/templates/qquickcontainer.cpp @@ -51,6 +51,8 @@ QT_BEGIN_NAMESPACE Container is the base type of container-like user interface controls. + \labs + \sa {Container Controls} */ diff --git a/src/templates/qquickcontrol.cpp b/src/templates/qquickcontrol.cpp index 6914037d..42ab4c70 100644 --- a/src/templates/qquickcontrol.cpp +++ b/src/templates/qquickcontrol.cpp @@ -63,6 +63,8 @@ QT_BEGIN_NAMESPACE \brief A user interface control. Control is the base type of user interface controls. + + \labs */ QQuickControlPrivate::QQuickControlPrivate() : diff --git a/src/templates/qquickdial.cpp b/src/templates/qquickdial.cpp index 3c354be4..2ad86f45 100644 --- a/src/templates/qquickdial.cpp +++ b/src/templates/qquickdial.cpp @@ -70,6 +70,8 @@ QT_BEGIN_NAMESPACE \row \li Set \l value to \l to \li \c Qt.Key_End \endtable + \labs + \sa {Customizing Dial}, {Input Controls} */ @@ -427,27 +429,39 @@ void QQuickDial::setHandle(QQuickItem *handle) void QQuickDial::keyPressEvent(QKeyEvent *event) { Q_D(QQuickDial); - if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Down) { + switch (event->key()) { + case Qt::Key_Left: + case Qt::Key_Down: setPressed(true); if (isMirrored()) increase(); else decrease(); - } else if (event->key() == Qt::Key_Right || event->key() == Qt::Key_Up) { + break; + + case Qt::Key_Right: + case Qt::Key_Up: setPressed(true); if (isMirrored()) decrease(); else increase(); - } else if (event->key() == Qt::Key_Home) { + break; + + case Qt::Key_Home: setPressed(true); setValue(isMirrored() ? d->to : d->from); - } else if (event->key() == Qt::Key_End) { + break; + + case Qt::Key_End: setPressed(true); setValue(isMirrored() ? d->from : d->to); - } else { + break; + + default: event->ignore(); QQuickControl::keyPressEvent(event); + break; } } diff --git a/src/templates/qquickdrawer.cpp b/src/templates/qquickdrawer.cpp index e0216872..2eb12676 100644 --- a/src/templates/qquickdrawer.cpp +++ b/src/templates/qquickdrawer.cpp @@ -80,6 +80,8 @@ QT_BEGIN_NAMESPACE If you would like the application's contents to stay where they are when the drawer is opened, don't apply a translation. + \labs + \sa SwipeView, {Customizing Drawer}, {Navigation Controls}, {Container Controls} */ diff --git a/src/templates/qquickframe.cpp b/src/templates/qquickframe.cpp index 68be30a2..6ca9da0e 100644 --- a/src/templates/qquickframe.cpp +++ b/src/templates/qquickframe.cpp @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-frame.qml 1 + \labs + \sa {Customizing Frame}, {Container Controls} */ diff --git a/src/templates/qquickgroupbox.cpp b/src/templates/qquickgroupbox.cpp index d324bb15..011245b1 100644 --- a/src/templates/qquickgroupbox.cpp +++ b/src/templates/qquickgroupbox.cpp @@ -75,6 +75,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-groupbox-checkable.qml 1 + \labs + \sa CheckBox, {Customizing GroupBox}, {Container Controls} */ diff --git a/src/templates/qquickitemdelegate.cpp b/src/templates/qquickitemdelegate.cpp index 7e13b638..f25a117f 100644 --- a/src/templates/qquickitemdelegate.cpp +++ b/src/templates/qquickitemdelegate.cpp @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-itemdelegate.qml 1 + \labs + \sa {Customizing ItemDelegate} */ diff --git a/src/templates/qquicklabel.cpp b/src/templates/qquicklabel.cpp index e749645c..8420deb1 100644 --- a/src/templates/qquicklabel.cpp +++ b/src/templates/qquicklabel.cpp @@ -65,6 +65,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-label.qml 1 + \labs + \sa {Customizing Label} */ diff --git a/src/templates/qquickmenu.cpp b/src/templates/qquickmenu.cpp index 69a409eb..beda1489 100644 --- a/src/templates/qquickmenu.cpp +++ b/src/templates/qquickmenu.cpp @@ -85,6 +85,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing Menu}, {Menu Controls} */ @@ -106,6 +108,8 @@ void QQuickMenuPrivate::insertItem(int index, QQuickItem *item) { contentData.append(item); item->setParentItem(contentItem); + if (complete) + resizeItem(item); QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); contentModel->insert(index, item); } @@ -124,6 +128,27 @@ void QQuickMenuPrivate::removeItem(int index, QQuickItem *item) contentModel->remove(index); } +void QQuickMenuPrivate::resizeItem(QQuickItem *item) +{ + if (!item || !contentItem) + return; + + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + if (!p->widthValid) { + item->setWidth(contentItem->width()); + p->widthValid = false; + } +} + +void QQuickMenuPrivate::resizeItems() +{ + if (!contentModel) + return; + + for (int i = 0; i < contentModel->count(); ++i) + resizeItem(itemAt(i)); +} + void QQuickMenuPrivate::itemChildAdded(QQuickItem *, QQuickItem *child) { // add dynamically reparented items (eg. by a Repeater) @@ -157,32 +182,10 @@ void QQuickMenuPrivate::itemDestroyed(QQuickItem *item) removeItem(index, item); } -void QQuickMenuPrivate::onContentItemChanged() +void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) { - Q_Q(QQuickMenu); - if (contentItem) { - contentItem->installEventFilter(q); - contentItem->setFlag(QQuickItem::ItemIsFocusScope); - contentItem->setActiveFocusOnTab(true); - - // Trying to give active focus to the contentItem (ListView, by default) - // when the menu first opens, without also giving it to the first delegate item - // doesn't seem to be possible, but this is what we need to do. QMenu behaves - // similarly to this; it receives focus if a button that has it as a menu is clicked, - // and only after pressing tab is the first menu item then given active focus. - if (!dummyFocusItem) { - dummyFocusItem = new QQuickItem(contentItem); - dummyFocusItem->setObjectName(QStringLiteral("dummyMenuFocusItem")); - } else { - dummyFocusItem->setParentItem(contentItem); - } - - dummyFocusItem->setActiveFocusOnTab(true); - dummyFocusItem->stackBefore(contentItem->childItems().first()); - - QObjectPrivate::connect(q, &QQuickMenu::visibleChanged, this, &QQuickMenuPrivate::onMenuVisibleChanged); - QObjectPrivate::connect(dummyFocusItem, &QQuickItem::activeFocusChanged, this, &QQuickMenuPrivate::maybeUnsetDummyFocusOnTab); - } + if (complete) + resizeItems(); } void QQuickMenuPrivate::onItemPressed() @@ -300,7 +303,7 @@ QQuickMenu::QQuickMenu(QObject *parent) : Q_D(QQuickMenu); connect(this, &QQuickMenu::pressedOutside, this, &QQuickMenu::close); connect(this, &QQuickMenu::releasedOutside, this, &QQuickMenu::close); - QObjectPrivate::connect(this, &QQuickMenu::contentItemChanged, d, &QQuickMenuPrivate::onContentItemChanged); + QObjectPrivate::connect(this, &QQuickMenu::visibleChanged, d, &QQuickMenuPrivate::onMenuVisibleChanged); } /*! @@ -442,6 +445,47 @@ void QQuickMenu::setTitle(QString &title) emit titleChanged(); } +void QQuickMenu::componentComplete() +{ + Q_D(QQuickMenu); + QQuickPopup::componentComplete(); + d->resizeItems(); +} + +void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_D(QQuickMenu); + QQuickPopup::contentItemChange(newItem, oldItem); + if (oldItem) { + oldItem->removeEventFilter(this); + if (d->dummyFocusItem) + QObjectPrivate::disconnect(d->dummyFocusItem.data(), &QQuickItem::activeFocusChanged, d, &QQuickMenuPrivate::maybeUnsetDummyFocusOnTab); + } + + if (newItem) { + newItem->installEventFilter(this); + newItem->setFlag(QQuickItem::ItemIsFocusScope); + newItem->setActiveFocusOnTab(true); + + // Trying to give active focus to the contentItem (ListView, by default) + // when the menu first opens, without also giving it to the first delegate item + // doesn't seem to be possible, but this is what we need to do. QMenu behaves + // similarly to this; it receives focus if a button that has it as a menu is clicked, + // and only after pressing tab is the first menu item then given active focus. + if (!d->dummyFocusItem) { + d->dummyFocusItem = new QQuickItem(newItem); + d->dummyFocusItem->setObjectName(QStringLiteral("dummyMenuFocusItem")); + } else { + d->dummyFocusItem->setParentItem(newItem); + } + + d->dummyFocusItem->setActiveFocusOnTab(true); + d->dummyFocusItem->stackBefore(newItem->childItems().first()); + + QObjectPrivate::connect(d->dummyFocusItem.data(), &QQuickItem::activeFocusChanged, d, &QQuickMenuPrivate::maybeUnsetDummyFocusOnTab); + } +} + bool QQuickMenu::eventFilter(QObject *object, QEvent *event) { Q_D(QQuickMenu); @@ -458,17 +502,23 @@ bool QQuickMenu::eventFilter(QObject *object, QEvent *event) // only allow flicking with the mouse when there are too many menu items to be // shown at once. QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); - if (keyEvent->key() == Qt::Key_Up) { + switch (keyEvent->key()) { + case Qt::Key_Up: if (d->contentItem->metaObject()->indexOfMethod("decrementCurrentIndex()") != -1) QMetaObject::invokeMethod(d->contentItem, "decrementCurrentIndex"); return true; - } else if (keyEvent->key() == Qt::Key_Down) { + + case Qt::Key_Down: if (d->contentItem->metaObject()->indexOfMethod("incrementCurrentIndex()") != -1) QMetaObject::invokeMethod(d->contentItem, "incrementCurrentIndex"); return true; - } else if (keyEvent->key() == Qt::Key_Escape) { + + case Qt::Key_Escape: close(); return true; + + default: + break; } return false; diff --git a/src/templates/qquickmenu_p.h b/src/templates/qquickmenu_p.h index a54cafbd..ec417d16 100644 --- a/src/templates/qquickmenu_p.h +++ b/src/templates/qquickmenu_p.h @@ -82,6 +82,8 @@ public: void setTitle(QString &title); protected: + void componentComplete() override; + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; bool eventFilter(QObject *object, QEvent *event) override; Q_SIGNALS: diff --git a/src/templates/qquickmenu_p_p.h b/src/templates/qquickmenu_p_p.h index e06c0299..505f3cb9 100644 --- a/src/templates/qquickmenu_p_p.h +++ b/src/templates/qquickmenu_p_p.h @@ -49,6 +49,7 @@ // #include <QtCore/qvector.h> +#include <QtCore/qpointer.h> #include <QtQuick/private/qquickitemchangelistener_p.h> #include <QtLabsTemplates/private/qquickpopup_p_p.h> @@ -69,12 +70,15 @@ public: void moveItem(int from, int to); void removeItem(int index, QQuickItem *item); + void resizeItem(QQuickItem *item); + void resizeItems(); + void itemChildAdded(QQuickItem *item, QQuickItem *child) override; void itemSiblingOrderChanged(QQuickItem *item) override; void itemParentChanged(QQuickItem *item, QQuickItem *parent) override; void itemDestroyed(QQuickItem *item) override; + void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry) override; - void onContentItemChanged(); void onItemPressed(); void onItemActiveFocusChanged(); void onMenuVisibleChanged(); @@ -87,7 +91,7 @@ public: QVector<QObject *> contentData; QQmlObjectModel *contentModel; - QQuickItem *dummyFocusItem; + QPointer<QQuickItem> dummyFocusItem; bool ignoreActiveFocusChanges; QString title; }; diff --git a/src/templates/qquickmenuitem.cpp b/src/templates/qquickmenuitem.cpp index f6cfda4c..d784af02 100644 --- a/src/templates/qquickmenuitem.cpp +++ b/src/templates/qquickmenuitem.cpp @@ -75,6 +75,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing MenuItem}, {Menu Controls} */ diff --git a/src/templates/qquickoverlay.cpp b/src/templates/qquickoverlay.cpp index 5455676f..8b19e8e9 100644 --- a/src/templates/qquickoverlay.cpp +++ b/src/templates/qquickoverlay.cpp @@ -240,6 +240,12 @@ void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event) emit released(); } +void QQuickOverlay::wheelEvent(QWheelEvent *event) +{ + Q_D(QQuickOverlay); + event->setAccepted(d->modalPopups > 0); +} + bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) { Q_D(QQuickOverlay); @@ -255,11 +261,11 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) const QQuickItemPrivate *priv = QQuickItemPrivate::get(this); const QList<QQuickItem *> &sortedChildren = priv->paintOrderChildItems(); for (int i = sortedChildren.count() - 1; i >= 0; --i) { - QQuickItem *contentItem = sortedChildren[i]; - if (contentItem == item) + QQuickItem *popupItem = sortedChildren[i]; + if (popupItem == item) break; - QQuickPopup *popup = d->popups.value(contentItem); + QQuickPopup *popup = d->popups.value(popupItem); if (popup) { emit popup->pressedOutside(); diff --git a/src/templates/qquickoverlay_p.h b/src/templates/qquickoverlay_p.h index b532720f..f5ce54f6 100644 --- a/src/templates/qquickoverlay_p.h +++ b/src/templates/qquickoverlay_p.h @@ -80,6 +80,7 @@ protected: void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; + void wheelEvent(QWheelEvent *event) override; bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; private: diff --git a/src/templates/qquickpageindicator.cpp b/src/templates/qquickpageindicator.cpp index 400a5237..1333c245 100644 --- a/src/templates/qquickpageindicator.cpp +++ b/src/templates/qquickpageindicator.cpp @@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-pageindicator.qml 1 + \labs + \sa SwipeView, {Customizing PageIndicator}, {Indicator Controls} */ diff --git a/src/templates/qquickpane.cpp b/src/templates/qquickpane.cpp index bbec8e42..c660220c 100644 --- a/src/templates/qquickpane.cpp +++ b/src/templates/qquickpane.cpp @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-pane.qml 1 + \labs + \sa {Customizing Pane}, {Container Controls} */ diff --git a/src/templates/qquickpopup.cpp b/src/templates/qquickpopup.cpp index 87c63f8d..93e5a63a 100644 --- a/src/templates/qquickpopup.cpp +++ b/src/templates/qquickpopup.cpp @@ -55,34 +55,400 @@ QT_BEGIN_NAMESPACE \brief A popup control. Popup is the base type of popup-like user interface controls. + + \labs */ +static const QQuickItemPrivate::ChangeTypes AncestorChangeTypes = QQuickItemPrivate::Geometry + | QQuickItemPrivate::Parent + | QQuickItemPrivate::Children; + +static const QQuickItemPrivate::ChangeTypes ItemChangeTypes = QQuickItemPrivate::Geometry + | QQuickItemPrivate::Parent + | QQuickItemPrivate::Destroyed; + QQuickPopupPrivate::QQuickPopupPrivate() : QObjectPrivate() , focus(false) , modal(false) + , hasTopPadding(false) + , hasLeftPadding(false) + , hasRightPadding(false) + , hasBottomPadding(false) + , padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , contentWidth(0) + , contentHeight(0) + , parentItem(nullptr) + , background(nullptr) , contentItem(nullptr) , overlay(nullptr) , enter(nullptr) , exit(nullptr) + , popupItem(nullptr) + , positioner(this) , transitionManager(this) { } +void QQuickPopupPrivate::init() +{ + Q_Q(QQuickPopup); + popupItem = new QQuickPopupItem(q); + popupItem->setParent(q); + q->setParentItem(qobject_cast<QQuickItem *>(parent)); +} + void QQuickPopupPrivate::finalizeEnterTransition() { if (focus) - contentItem->setFocus(true); + popupItem->setFocus(true); } void QQuickPopupPrivate::finalizeExitTransition() { Q_Q(QQuickPopup); overlay = nullptr; - contentItem->setParentItem(nullptr); + positioner.setParentItem(nullptr); + popupItem->setParentItem(nullptr); emit q->visibleChanged(); } +void QQuickPopupPrivate::resizeBackground() +{ + Q_Q(QQuickPopup); + if (background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(background); + if (!p->widthValid && qFuzzyIsNull(background->x())) { + background->setWidth(q->width()); + p->widthValid = false; + } + if (!p->heightValid && qFuzzyIsNull(background->y())) { + background->setHeight(q->height()); + p->heightValid = false; + } + } +} + +void QQuickPopupPrivate::resizeContent() +{ + Q_Q(QQuickPopup); + if (contentItem) { + contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding())); + contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight())); + } +} + +void QQuickPopupPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldPadding = q->topPadding(); + topPadding = value; + hasTopPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->topPaddingChanged(); + emit q->availableHeightChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(leftPadding, oldPadding, rightPadding, bottomPadding)); + } +} + +void QQuickPopupPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldPadding = q->leftPadding(); + leftPadding = value; + hasLeftPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->leftPaddingChanged(); + emit q->availableWidthChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(oldPadding, topPadding, rightPadding, bottomPadding)); + } +} + +void QQuickPopupPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldPadding = q->rightPadding(); + rightPadding = value; + hasRightPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->rightPaddingChanged(); + emit q->availableWidthChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(leftPadding, topPadding, oldPadding, bottomPadding)); + } +} + +void QQuickPopupPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldPadding = q->bottomPadding(); + bottomPadding = value; + hasBottomPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + emit q->bottomPaddingChanged(); + emit q->availableHeightChanged(); + q->paddingChange(QMarginsF(leftPadding, topPadding, rightPadding, bottomPadding), + QMarginsF(leftPadding, topPadding, rightPadding, oldPadding)); + } +} + +class QQuickPopupItemPrivate : public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickPopupItem) + +public: + QQuickPopupItemPrivate(QQuickPopup *popup); + + void implicitWidthChanged() override; + void implicitHeightChanged() override; + + QQuickPopup *popup; +}; + +QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup) : popup(popup) +{ +} + +void QQuickPopupItemPrivate::implicitWidthChanged() +{ + emit popup->implicitHeightChanged(); +} + +void QQuickPopupItemPrivate::implicitHeightChanged() +{ + emit popup->implicitHeightChanged(); +} + +QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup) : + QQuickItem(*(new QQuickPopupItemPrivate(popup))) +{ + setAcceptedMouseButtons(Qt::AllButtons); +} + +void QQuickPopupItem::focusInEvent(QFocusEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->focusInEvent(event); +} + +void QQuickPopupItem::focusOutEvent(QFocusEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->focusOutEvent(event); +} + +void QQuickPopupItem::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->keyPressEvent(event); +} + +void QQuickPopupItem::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->keyReleaseEvent(event); +} + +void QQuickPopupItem::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mousePressEvent(event); +} + +void QQuickPopupItem::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mouseMoveEvent(event); +} + +void QQuickPopupItem::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mouseReleaseEvent(event); +} + +void QQuickPopupItem::mouseDoubleClickEvent(QMouseEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->mouseDoubleClickEvent(event); +} + +void QQuickPopupItem::mouseUngrabEvent() +{ + Q_D(QQuickPopupItem); + d->popup->mouseUngrabEvent(); +} + +void QQuickPopupItem::wheelEvent(QWheelEvent *event) +{ + Q_D(QQuickPopupItem); + d->popup->wheelEvent(event); +} + +void QQuickPopupItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickPopupItem); + d->popup->geometryChanged(newGeometry, oldGeometry); +} + +QQuickPopupPositioner::QQuickPopupPositioner(QQuickPopupPrivate *popup) : + m_x(0), + m_y(0), + m_parentItem(nullptr), + m_popup(popup) +{ +} + +QQuickPopupPositioner::~QQuickPopupPositioner() +{ + if (m_parentItem) { + QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes); + removeAncestorListeners(m_parentItem->parentItem()); + } +} + +qreal QQuickPopupPositioner::x() const +{ + return m_x; +} + +void QQuickPopupPositioner::setX(qreal x) +{ + if (m_x != x) { + m_x = x; + repositionPopup(); + } +} + +qreal QQuickPopupPositioner::y() const +{ + return m_y; +} + +void QQuickPopupPositioner::setY(qreal y) +{ + if (m_y != y) { + m_y = y; + repositionPopup(); + } +} + +QQuickItem *QQuickPopupPositioner::parentItem() const +{ + return m_parentItem; +} + +void QQuickPopupPositioner::setParentItem(QQuickItem *parent) +{ + if (m_parentItem == parent) + return; + + if (m_parentItem) { + QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes); + removeAncestorListeners(m_parentItem->parentItem()); + } + + m_parentItem = parent; + + if (!parent) + return; + + QQuickItemPrivate::get(parent)->addItemChangeListener(this, ItemChangeTypes); + addAncestorListeners(parent->parentItem()); + + repositionPopup(); +} + +void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) +{ + repositionPopup(); +} + +void QQuickPopupPositioner::itemParentChanged(QQuickItem *, QQuickItem *parent) +{ + addAncestorListeners(parent); +} + +void QQuickPopupPositioner::itemChildRemoved(QQuickItem *, QQuickItem *child) +{ + if (isAncestor(child)) + removeAncestorListeners(child); +} + +void QQuickPopupPositioner::itemDestroyed(QQuickItem *item) +{ + Q_ASSERT(m_parentItem == item); + + m_parentItem = nullptr; + QQuickItemPrivate::get(item)->removeItemChangeListener(this, ItemChangeTypes); + removeAncestorListeners(item->parentItem()); +} + +void QQuickPopupPositioner::repositionPopup() +{ + QRectF rect(m_x, m_y, m_popup->popupItem->width(), m_popup->popupItem->height()); + if (m_parentItem) { + rect = m_parentItem->mapRectToScene(rect); + + QQuickWindow *window = m_parentItem->window(); + if (window) { + if (rect.top() < 0 || rect.bottom() > window->height()) { + // if the popup doesn't fit on the screen, try flipping it around (below <-> above) + QRectF flipped = m_parentItem->mapRectToScene(QRectF(m_x, m_parentItem->height() - m_y - rect.height(), rect.width(), rect.height())); + if (flipped.y() >= 0 && flipped.bottom() < window->height()) + rect = flipped; + } + } + } + + m_popup->popupItem->setPosition(rect.topLeft()); +} + +void QQuickPopupPositioner::removeAncestorListeners(QQuickItem *item) +{ + if (item == m_parentItem) + return; + + QQuickItem *p = item; + while (p) { + QQuickItemPrivate::get(p)->removeItemChangeListener(this, AncestorChangeTypes); + p = p->parentItem(); + } +} + +void QQuickPopupPositioner::addAncestorListeners(QQuickItem *item) +{ + if (item == m_parentItem) + return; + + QQuickItem *p = item; + while (p) { + QQuickItemPrivate::get(p)->addItemChangeListener(this, AncestorChangeTypes); + p = p->parentItem(); + } +} + +// TODO: use QQuickItem::isAncestorOf() in dev/5.7 +bool QQuickPopupPositioner::isAncestor(QQuickItem *item) const +{ + if (!m_parentItem) + return false; + + QQuickItem *parent = m_parentItem->parentItem(); + while (parent) { + if (parent == item) + return true; + parent = parent->parentItem(); + } + return false; +} + QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup) : QQuickTransitionManager() , state(Off) @@ -96,7 +462,7 @@ void QQuickPopupTransitionManager::transitionEnter() return; QList<QQuickStateAction> actions; state = Enter; - transition(actions, popup->enter, popup->contentItem); + transition(actions, popup->enter, popup->popupItem); } void QQuickPopupTransitionManager::transitionExit() @@ -105,7 +471,7 @@ void QQuickPopupTransitionManager::transitionExit() return; QList<QQuickStateAction> actions; state = Exit; - transition(actions, popup->exit, popup->contentItem); + transition(actions, popup->exit, popup->popupItem); } void QQuickPopupTransitionManager::finished() @@ -121,11 +487,21 @@ void QQuickPopupTransitionManager::finished() QQuickPopup::QQuickPopup(QObject *parent) : QObject(*(new QQuickPopupPrivate), parent) { + Q_D(QQuickPopup); + d->init(); } QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent) : QObject(dd, parent) { + Q_D(QQuickPopup); + d->init(); +} + +QQuickPopup::~QQuickPopup() +{ + Q_D(QQuickPopup); + d->positioner.setParentItem(nullptr); } /*! @@ -136,13 +512,8 @@ QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent) void QQuickPopup::open() { Q_D(QQuickPopup); - if (!d->contentItem) { - qmlInfo(this) << "no popup content to show."; - return; - } if (d->overlay) { - // FIXME qmlInfo needs to know about QQuickWindow and/or QObject - static_cast<QDebug>(qmlInfo(this) << "popup already open in window") << d->overlay->window(); + // popup already open return; } @@ -172,7 +543,11 @@ void QQuickPopup::open() } d->overlay = static_cast<QQuickOverlay *>(applicationWindow->overlay()); - d->contentItem->setParentItem(d->overlay); + d->popupItem->setParentItem(d->overlay); + d->positioner.setParentItem(d->parentItem); + // TODO: add Popup::transformOrigin? + if (d->contentItem) + d->popupItem->setTransformOrigin(d->contentItem->transformOrigin()); emit aboutToShow(); d->transitionManager.transitionEnter(); emit visibleChanged(); @@ -187,17 +562,406 @@ void QQuickPopup::close() { Q_D(QQuickPopup); if (!d->overlay) { - // TODO This could mean we opened the popup item in a plain QQuickWindow - qmlInfo(this) << "trying to close non-visible Popup."; + // popup already closed return; } - d->contentItem->setFocus(false); + d->popupItem->setFocus(false); emit aboutToHide(); d->transitionManager.transitionExit(); } /*! + \qmlproperty real Qt.labs.controls::Popup::x + + This property holds the x-coordinate of the popup. +*/ +qreal QQuickPopup::x() const +{ + Q_D(const QQuickPopup); + return d->positioner.x(); +} + +void QQuickPopup::setX(qreal x) +{ + Q_D(QQuickPopup); + d->positioner.setX(x); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::y + + This property holds the y-coordinate of the popup. +*/ +qreal QQuickPopup::y() const +{ + Q_D(const QQuickPopup); + return d->positioner.y(); +} + +void QQuickPopup::setY(qreal y) +{ + Q_D(QQuickPopup); + d->positioner.setY(y); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::width + + This property holds the width of the popup. +*/ +qreal QQuickPopup::width() const +{ + Q_D(const QQuickPopup); + return d->popupItem->width(); +} + +void QQuickPopup::setWidth(qreal width) +{ + Q_D(QQuickPopup); + d->popupItem->setWidth(width); +} + +void QQuickPopup::resetWidth() +{ + Q_D(QQuickPopup); + d->popupItem->resetWidth(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::height + + This property holds the height of the popup. +*/ +qreal QQuickPopup::height() const +{ + Q_D(const QQuickPopup); + return d->popupItem->height(); +} + +void QQuickPopup::setHeight(qreal height) +{ + Q_D(QQuickPopup); + d->popupItem->setHeight(height); +} + +void QQuickPopup::resetHeight() +{ + Q_D(QQuickPopup); + d->popupItem->resetHeight(); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::implicitWidth + + This property holds the implicit width of the popup. +*/ +qreal QQuickPopup::implicitWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitWidth(); +} + +void QQuickPopup::setImplicitWidth(qreal width) +{ + Q_D(QQuickPopup); + d->popupItem->setImplicitWidth(width); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::implicitHeight + + This property holds the implicit height of the popup. +*/ +qreal QQuickPopup::implicitHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitHeight(); +} + +void QQuickPopup::setImplicitHeight(qreal height) +{ + Q_D(QQuickPopup); + d->popupItem->setImplicitHeight(height); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::contentWidth + + This property holds the content width. It is used for calculating the + total implicit width of the Popup. + + \note If only a single item is used within the Popup, the implicit width + of its contained item is used as the content width. +*/ +qreal QQuickPopup::contentWidth() const +{ + Q_D(const QQuickPopup); + return d->contentWidth; +} + +void QQuickPopup::setContentWidth(qreal width) +{ + Q_D(QQuickPopup); + if (d->contentWidth != width) { + d->contentWidth = width; + emit contentWidthChanged(); + } +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::contentHeight + + This property holds the content height. It is used for calculating the + total implicit height of the Popup. + + \note If only a single item is used within the Popup, the implicit height + of its contained item is used as the content height. +*/ +qreal QQuickPopup::contentHeight() const +{ + Q_D(const QQuickPopup); + return d->contentHeight; +} + +void QQuickPopup::setContentHeight(qreal height) +{ + Q_D(QQuickPopup); + if (d->contentHeight != height) { + d->contentHeight = height; + emit contentHeightChanged(); + } +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::availableWidth + + This property holds the width available after deducting horizontal padding. + + \sa padding, leftPadding, rightPadding +*/ +qreal QQuickPopup::availableWidth() const +{ + return qMax<qreal>(0.0, width() - leftPadding() - rightPadding()); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::availableHeight + + This property holds the height available after deducting vertical padding. + + \sa padding, topPadding, bottomPadding +*/ +qreal QQuickPopup::availableHeight() const +{ + return qMax<qreal>(0.0, height() - topPadding() - bottomPadding()); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::padding + + This property holds the default padding. + + \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding +*/ +qreal QQuickPopup::padding() const +{ + Q_D(const QQuickPopup); + return d->padding; +} + +void QQuickPopup::setPadding(qreal padding) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->padding, padding)) + return; + QMarginsF oldPadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); + d->padding = padding; + emit paddingChanged(); + QMarginsF newPadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); + if (!qFuzzyCompare(newPadding.top(), oldPadding.top())) + emit topPaddingChanged(); + if (!qFuzzyCompare(newPadding.left(), oldPadding.left())) + emit leftPaddingChanged(); + if (!qFuzzyCompare(newPadding.right(), oldPadding.right())) + emit rightPaddingChanged(); + if (!qFuzzyCompare(newPadding.bottom(), oldPadding.bottom())) + emit bottomPaddingChanged(); + if (!qFuzzyCompare(newPadding.top(), oldPadding.top()) || !qFuzzyCompare(newPadding.bottom(), oldPadding.bottom())) + emit availableHeightChanged(); + if (!qFuzzyCompare(newPadding.left(), oldPadding.left()) || !qFuzzyCompare(newPadding.right(), oldPadding.right())) + emit availableWidthChanged(); + paddingChange(newPadding, oldPadding); +} + +void QQuickPopup::resetPadding() +{ + setPadding(0); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::topPadding + + This property holds the top padding. + + \sa padding, bottomPadding, availableHeight +*/ +qreal QQuickPopup::topPadding() const +{ + Q_D(const QQuickPopup); + if (d->hasTopPadding) + return d->topPadding; + return d->padding; +} + +void QQuickPopup::setTopPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->setTopPadding(padding); +} + +void QQuickPopup::resetTopPadding() +{ + Q_D(QQuickPopup); + d->setTopPadding(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::leftPadding + + This property holds the left padding. + + \sa padding, rightPadding, availableWidth +*/ +qreal QQuickPopup::leftPadding() const +{ + Q_D(const QQuickPopup); + if (d->hasLeftPadding) + return d->leftPadding; + return d->padding; +} + +void QQuickPopup::setLeftPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->setLeftPadding(padding); +} + +void QQuickPopup::resetLeftPadding() +{ + Q_D(QQuickPopup); + d->setLeftPadding(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::rightPadding + + This property holds the right padding. + + \sa padding, leftPadding, availableWidth +*/ +qreal QQuickPopup::rightPadding() const +{ + Q_D(const QQuickPopup); + if (d->hasRightPadding) + return d->rightPadding; + return d->padding; +} + +void QQuickPopup::setRightPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->setRightPadding(padding); +} + +void QQuickPopup::resetRightPadding() +{ + Q_D(QQuickPopup); + d->setRightPadding(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::bottomPadding + + This property holds the bottom padding. + + \sa padding, topPadding, availableHeight +*/ +qreal QQuickPopup::bottomPadding() const +{ + Q_D(const QQuickPopup); + if (d->hasBottomPadding) + return d->bottomPadding; + return d->padding; +} + +void QQuickPopup::setBottomPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->setBottomPadding(padding); +} + +void QQuickPopup::resetBottomPadding() +{ + Q_D(QQuickPopup); + d->setBottomPadding(0, true); +} + +/*! + \qmlproperty Item Qt.labs.popups::Popup::parent + + This property holds the parent item. +*/ +QQuickItem *QQuickPopup::parentItem() const +{ + Q_D(const QQuickPopup); + return d->parentItem; +} + +void QQuickPopup::setParentItem(QQuickItem *parent) +{ + Q_D(QQuickPopup); + if (d->parentItem != parent) { + d->parentItem = parent; + if (d->positioner.parentItem()) + d->positioner.setParentItem(parent); + emit parentChanged(); + } +} + +/*! + \qmlproperty Item Qt.labs.popups::Popup::background + + This property holds the background item. + + \note If the background item has no explicit size specified, it automatically + follows the popup's size. In most cases, there is no need to specify + width or height for a background item. +*/ +QQuickItem *QQuickPopup::background() const +{ + Q_D(const QQuickPopup); + return d->background; +} + +void QQuickPopup::setBackground(QQuickItem *background) +{ + Q_D(QQuickPopup); + if (d->background != background) { + delete d->background; + d->background = background; + if (background) { + background->setParentItem(d->popupItem); + if (qFuzzyIsNull(background->z())) + background->setZ(-1); + if (isComponentComplete()) + d->resizeBackground(); + } + emit backgroundChanged(); + } +} + +/*! \qmlproperty Item Qt.labs.controls::Popup::contentItem This property holds the content item of the popup. @@ -222,15 +986,55 @@ void QQuickPopup::setContentItem(QQuickItem *item) return; } if (d->contentItem != item) { + contentItemChange(item, d->contentItem); delete d->contentItem; d->contentItem = item; - if (item) + if (item) { + item->setParentItem(d->popupItem); QQuickItemPrivate::get(item)->isTabFence = true; + if (isComponentComplete()) + d->resizeContent(); + } emit contentItemChanged(); } } /*! + \qmlproperty list<Object> Qt.labs.controls::Popup::contentData + \default + + This property holds the list of content data. + + \sa Item::data +*/ +QQmlListProperty<QObject> QQuickPopup::contentData() +{ + Q_D(QQuickPopup); + return QQmlListProperty<QObject>(d->contentItem, nullptr, + QQuickItemPrivate::data_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + QQuickItemPrivate::data_clear); +} + +/*! + \qmlproperty list<Item> Qt.labs.controls::Popup::contentChildren + + This property holds the list of content children. + + \sa Item::children +*/ +QQmlListProperty<QQuickItem> QQuickPopup::contentChildren() +{ + Q_D(QQuickPopup); + return QQmlListProperty<QQuickItem>(d->contentItem, nullptr, + QQuickItemPrivate::children_append, + QQuickItemPrivate::children_count, + QQuickItemPrivate::children_at, + QQuickItemPrivate::children_clear); +} + +/*! \qmlproperty bool Qt.labs.controls::Popup::focus This property holds whether the popup has focus. @@ -281,6 +1085,14 @@ bool QQuickPopup::isVisible() const return d->overlay != nullptr /*&& !d->transitionManager.isRunning()*/; } +void QQuickPopup::setVisible(bool visible) +{ + if (visible) + open(); + else + close(); +} + /*! \qmlproperty Transition Qt.labs.controls::Popup::enter @@ -323,6 +1135,102 @@ void QQuickPopup::setExit(QQuickTransition *transition) emit exitChanged(); } +void QQuickPopup::classBegin() +{ +} + +void QQuickPopup::componentComplete() +{ + Q_D(QQuickPopup); + d->complete = true; + if (!parentItem()) + setParentItem(qobject_cast<QQuickItem *>(parent())); +} + +bool QQuickPopup::isComponentComplete() const +{ + Q_D(const QQuickPopup); + return d->complete; +} + +void QQuickPopup::focusInEvent(QFocusEvent *event) +{ + event->accept(); +} + +void QQuickPopup::focusOutEvent(QFocusEvent *event) +{ + event->accept(); +} + +void QQuickPopup::keyPressEvent(QKeyEvent *event) +{ + event->accept(); +} + +void QQuickPopup::keyReleaseEvent(QKeyEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mousePressEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseMoveEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseReleaseEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseUngrabEvent() +{ +} + +void QQuickPopup::wheelEvent(QWheelEvent *event) +{ + event->accept(); +} + +void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_UNUSED(newItem); + Q_UNUSED(oldItem); +} + +void QQuickPopup::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickPopup); + d->resizeBackground(); + d->resizeContent(); + if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) { + emit widthChanged(); + emit availableWidthChanged(); + } + if (!qFuzzyCompare(newGeometry.height(), oldGeometry.height())) { + emit heightChanged(); + emit availableHeightChanged(); + } +} + +void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) +{ + Q_D(QQuickPopup); + Q_UNUSED(newPadding); + Q_UNUSED(oldPadding); + d->resizeContent(); +} + QT_END_NAMESPACE #include "moc_qquickpopup_p.cpp" diff --git a/src/templates/qquickpopup_p.h b/src/templates/qquickpopup_p.h index 8eb5e150..e94b63f1 100644 --- a/src/templates/qquickpopup_p.h +++ b/src/templates/qquickpopup_p.h @@ -49,31 +49,116 @@ // #include <QtCore/qobject.h> +#include <QtCore/qmargins.h> +#include <QtGui/qevent.h> #include <QtLabsTemplates/private/qtlabstemplatesglobal_p.h> #include <QtQml/qqml.h> +#include <QtQml/qqmllist.h> +#include <QtQml/qqmlparserstatus.h> QT_BEGIN_NAMESPACE class QQuickItem; class QQuickPopupPrivate; class QQuickTransition; +class QQuickTransform; -class Q_LABSTEMPLATES_EXPORT QQuickPopup : public QObject +class Q_LABSTEMPLATES_EXPORT QQuickPopup : public QObject, public QQmlParserStatus { Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL) + Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL) + Q_PROPERTY(qreal width READ width WRITE setWidth RESET resetWidth NOTIFY widthChanged FINAL) + Q_PROPERTY(qreal height READ height WRITE setHeight RESET resetHeight NOTIFY heightChanged FINAL) + Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged FINAL) + Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged FINAL) + Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged FINAL) + Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged FINAL) + Q_PROPERTY(qreal availableWidth READ availableWidth NOTIFY availableWidthChanged FINAL) + Q_PROPERTY(qreal availableHeight READ availableHeight NOTIFY availableHeightChanged FINAL) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged FINAL) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged FINAL) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged FINAL) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged FINAL) + Q_PROPERTY(QQuickItem *parent READ parentItem WRITE setParentItem NOTIFY parentChanged FINAL) + Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL) Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged FINAL) + Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL) + Q_PROPERTY(QQmlListProperty<QQuickItem> contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL) Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged) Q_PROPERTY(bool modal READ isModal WRITE setModal NOTIFY modalChanged) - Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) Q_PROPERTY(QQuickTransition *enter READ enter WRITE setEnter NOTIFY enterChanged FINAL) Q_PROPERTY(QQuickTransition *exit READ exit WRITE setExit NOTIFY exitChanged FINAL) + Q_CLASSINFO("DefaultProperty", "contentData") public: explicit QQuickPopup(QObject *parent = nullptr); + ~QQuickPopup(); + + qreal x() const; + void setX(qreal x); + + qreal y() const; + void setY(qreal y); + + qreal width() const; + void setWidth(qreal width); + void resetWidth(); + + qreal height() const; + void setHeight(qreal height); + void resetHeight(); + + qreal implicitWidth() const; + void setImplicitWidth(qreal width); + + qreal implicitHeight() const; + void setImplicitHeight(qreal height); + + qreal contentWidth() const; + void setContentWidth(qreal width); + + qreal contentHeight() const; + void setContentHeight(qreal height); + + qreal availableWidth() const; + qreal availableHeight() const; + + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + + QQuickItem *parentItem() const; + void setParentItem(QQuickItem *parent); + + QQuickItem *background() const; + void setBackground(QQuickItem *background); QQuickItem *contentItem() const; void setContentItem(QQuickItem *item); + QQmlListProperty<QObject> contentData(); + QQmlListProperty<QQuickItem> contentChildren(); + bool hasFocus() const; void setFocus(bool focus); @@ -81,6 +166,7 @@ public: void setModal(bool modal); bool isVisible() const; + void setVisible(bool visible); QQuickTransition *enter() const; void setEnter(QQuickTransition *transition); @@ -93,7 +179,25 @@ public Q_SLOTS: void close(); Q_SIGNALS: + void xChanged(); + void yChanged(); + void widthChanged(); + void heightChanged(); + void implicitWidthChanged(); + void implicitHeightChanged(); + void contentWidthChanged(); + void contentHeightChanged(); + void availableWidthChanged(); + void availableHeightChanged(); + void paddingChanged(); + void topPaddingChanged(); + void leftPaddingChanged(); + void rightPaddingChanged(); + void bottomPaddingChanged(); + void parentChanged(); + void backgroundChanged(); void contentItemChanged(); + void contentChildrenChanged(); void focusChanged(); void modalChanged(); void visibleChanged(); @@ -110,9 +214,29 @@ Q_SIGNALS: protected: QQuickPopup(QQuickPopupPrivate &dd, QObject *parent); + void classBegin() override; + void componentComplete() override; + bool isComponentComplete() const; + + virtual void focusInEvent(QFocusEvent *event); + virtual void focusOutEvent(QFocusEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event); + virtual void mouseUngrabEvent(); + virtual void wheelEvent(QWheelEvent *event); + + virtual void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem); + virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + virtual void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding); + private: Q_DISABLE_COPY(QQuickPopup) Q_DECLARE_PRIVATE(QQuickPopup) + friend class QQuickPopupItem; }; QT_END_NAMESPACE diff --git a/src/templates/qquickpopup_p_p.h b/src/templates/qquickpopup_p_p.h index 3a5909b7..910fca9e 100644 --- a/src/templates/qquickpopup_p_p.h +++ b/src/templates/qquickpopup_p_p.h @@ -48,17 +48,21 @@ // We mean it. // +#include "qquickpopup_p.h" + #include <QtCore/private/qobject_p.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickitemchangelistener_p.h> #include <QtQuick/private/qquicktransitionmanager_p_p.h> QT_BEGIN_NAMESPACE -class QQuickItem; class QQuickTransition; class QQuickTransitionManager; class QQuickPopup; -class QQuickPopupPrivate; class QQuickOverlay; +class QQuickPopupPrivate; +class QQuickPopupItemPrivate; class QQuickPopupTransitionManager : public QQuickTransitionManager { @@ -80,6 +84,66 @@ private: QQuickPopupPrivate *popup; }; +class QQuickPopupItem : public QQuickItem +{ + Q_OBJECT + +public: + explicit QQuickPopupItem(QQuickPopup *popup); + +protected: + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; + void wheelEvent(QWheelEvent *event) override; + + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + +private: + Q_DECLARE_PRIVATE(QQuickPopupItem) +}; + +class QQuickPopupPositioner : public QQuickItemChangeListener +{ +public: + explicit QQuickPopupPositioner(QQuickPopupPrivate *popup); + ~QQuickPopupPositioner(); + + qreal x() const; + void setX(qreal x); + + qreal y() const; + void setY(qreal y); + + QQuickItem *parentItem() const; + void setParentItem(QQuickItem *parent); + +protected: + void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &); + void itemParentChanged(QQuickItem *, QQuickItem *parent); + void itemChildRemoved(QQuickItem *, QQuickItem *child); + void itemDestroyed(QQuickItem *item); + +private: + void repositionPopup(); + + void removeAncestorListeners(QQuickItem *item); + void addAncestorListeners(QQuickItem *item); + + bool isAncestor(QQuickItem *item) const; + + qreal m_x; + qreal m_y; + QQuickItem *m_parentItem; + QQuickPopupPrivate *m_popup; +}; + class QQuickPopupPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QQuickPopup) @@ -87,15 +151,46 @@ class QQuickPopupPrivate : public QObjectPrivate public: QQuickPopupPrivate(); + static QQuickPopupPrivate *get(QQuickPopup *popup) + { + return popup->d_func(); + } + + void init(); + void finalizeEnterTransition(); void finalizeExitTransition(); + void resizeBackground(); + void resizeContent(); + + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + bool focus; bool modal; + bool complete; + bool hasTopPadding; + bool hasLeftPadding; + bool hasRightPadding; + bool hasBottomPadding; + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + qreal contentWidth; + qreal contentHeight; + QQuickItem *parentItem; + QQuickItem *background; QQuickItem *contentItem; QQuickOverlay *overlay; QQuickTransition *enter; QQuickTransition *exit; + QQuickPopupItem *popupItem; + QQuickPopupPositioner positioner; QQuickPopupTransitionManager transitionManager; }; diff --git a/src/templates/qquickprogressbar.cpp b/src/templates/qquickprogressbar.cpp index 114b117e..cd490f50 100644 --- a/src/templates/qquickprogressbar.cpp +++ b/src/templates/qquickprogressbar.cpp @@ -62,6 +62,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing ProgressBar} */ diff --git a/src/templates/qquickradiobutton.cpp b/src/templates/qquickradiobutton.cpp index 9aca5808..7d7a64aa 100644 --- a/src/templates/qquickradiobutton.cpp +++ b/src/templates/qquickradiobutton.cpp @@ -84,6 +84,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa ButtonGroup, {Customizing RadioButton}, {Button Controls} */ diff --git a/src/templates/qquickrangeslider.cpp b/src/templates/qquickrangeslider.cpp index 0a16cafc..0dec63cb 100644 --- a/src/templates/qquickrangeslider.cpp +++ b/src/templates/qquickrangeslider.cpp @@ -73,6 +73,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing RangeSlider}, {Input Controls} */ diff --git a/src/templates/qquickscrollbar.cpp b/src/templates/qquickscrollbar.cpp index caabbcf7..ad7b0a6d 100644 --- a/src/templates/qquickscrollbar.cpp +++ b/src/templates/qquickscrollbar.cpp @@ -73,6 +73,8 @@ QT_BEGIN_NAMESPACE \li \l active \endlist + \labs + \sa ScrollIndicator, {Customizing ScrollBar}, {Indicator Controls} */ diff --git a/src/templates/qquickscrollindicator.cpp b/src/templates/qquickscrollindicator.cpp index 59f2acc0..5e210f09 100644 --- a/src/templates/qquickscrollindicator.cpp +++ b/src/templates/qquickscrollindicator.cpp @@ -73,6 +73,8 @@ QT_BEGIN_NAMESPACE \li \l active \endlist + \labs + \sa ScrollBar, {Customizing ScrollIndicator}, {Indicator Controls} */ diff --git a/src/templates/qquickslider.cpp b/src/templates/qquickslider.cpp index f1eca648..b109fc5a 100644 --- a/src/templates/qquickslider.cpp +++ b/src/templates/qquickslider.cpp @@ -68,6 +68,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing Slider}, {Input Controls} */ diff --git a/src/templates/qquickspinbox.cpp b/src/templates/qquickspinbox.cpp index 83eefbf3..31368a1a 100644 --- a/src/templates/qquickspinbox.cpp +++ b/src/templates/qquickspinbox.cpp @@ -80,6 +80,8 @@ static const int AUTO_REPEAT_INTERVAL = 100; \snippet qtlabscontrols-spinbox-textual.qml 1 + \labs + \sa Tumbler, {Customizing SpinBox} */ @@ -181,7 +183,7 @@ bool QQuickSpinBoxPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent q->setAccessibleProperty("pressed", pressed); if (pressed) startRepeatDelay(); - return up->isPressed() || down->isPressed(); + return pressed; } bool QQuickSpinBoxPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event) @@ -195,7 +197,7 @@ bool QQuickSpinBoxPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent * bool pressed = up->isPressed() || down->isPressed(); q->setAccessibleProperty("pressed", pressed); stopPressRepeat(); - return up->isPressed() || down->isPressed(); + return pressed; } bool QQuickSpinBoxPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event) diff --git a/src/templates/qquickstackview.cpp b/src/templates/qquickstackview.cpp index 29b631dc..b338f3bf 100644 --- a/src/templates/qquickstackview.cpp +++ b/src/templates/qquickstackview.cpp @@ -257,6 +257,8 @@ QT_BEGIN_NAMESPACE } \endqml + \labs + \sa {Customizing StackView}, {Navigation Controls}, {Container Controls} */ @@ -877,10 +879,18 @@ void QQuickStackView::geometryChanged(const QRectF &newGeometry, const QRectF &o } } -bool QQuickStackView::childMouseEventFilter(QQuickItem *, QEvent *) +bool QQuickStackView::childMouseEventFilter(QQuickItem *item, QEvent *event) { - // busy should be true if this function gets called - return true; + // in order to block accidental user interaction while busy/transitioning, + // StackView filters out childrens' mouse events. therefore we block all + // press events. however, since push() may be called from signal handlers + // such as onPressed or onDoubleClicked, we must let the current mouse + // grabber item receive the respective mouse release event to avoid + // breaking its state (QTBUG-50305). + if (event->type() == QEvent::MouseButtonPress) + return true; + QQuickWindow *window = item->window(); + return window && !window->mouseGrabberItem(); } void QQuickStackAttachedPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent) diff --git a/src/templates/qquickstackview_p.cpp b/src/templates/qquickstackview_p.cpp index a34b62e9..5d967a0e 100644 --- a/src/templates/qquickstackview_p.cpp +++ b/src/templates/qquickstackview_p.cpp @@ -83,18 +83,20 @@ QQuickStackElement::~QQuickStackElement() if (ownComponent) delete component; - if (ownItem && item) { - item->setParentItem(nullptr); - item->deleteLater(); - item = nullptr; - } else if (item) { - item->setVisible(false); - if (item->parentItem() != originalParent) { - item->setParentItem(originalParent); + if (item) { + if (ownItem) { + item->setParentItem(nullptr); + item->deleteLater(); + item = nullptr; } else { - QQuickStackAttached *attached = attachedStackObject(this); - if (attached) - QQuickStackAttachedPrivate::get(attached)->itemParentChanged(item, nullptr); + item->setVisible(false); + if (item->parentItem() != originalParent) { + item->setParentItem(originalParent); + } else { + QQuickStackAttached *attached = attachedStackObject(this); + if (attached) + QQuickStackAttachedPrivate::get(attached)->itemParentChanged(item, nullptr); + } } } diff --git a/src/templates/qquickswipeview.cpp b/src/templates/qquickswipeview.cpp index 40366af1..b73a8ac0 100644 --- a/src/templates/qquickswipeview.cpp +++ b/src/templates/qquickswipeview.cpp @@ -67,6 +67,8 @@ QT_BEGIN_NAMESPACE \l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove} pages dynamically at run time. + \labs + \sa TabBar, PageIndicator, {Customizing SwipeView}, {Navigation Controls}, {Container Controls} */ diff --git a/src/templates/qquickswitch.cpp b/src/templates/qquickswitch.cpp index a867ec70..8544d7ca 100644 --- a/src/templates/qquickswitch.cpp +++ b/src/templates/qquickswitch.cpp @@ -77,6 +77,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa {Customizing Switch}, {Button Controls} */ diff --git a/src/templates/qquicktabbar.cpp b/src/templates/qquicktabbar.cpp index d2362f0c..880a89e2 100644 --- a/src/templates/qquicktabbar.cpp +++ b/src/templates/qquicktabbar.cpp @@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-tabbar.qml 1 + \labs + \sa TabButton, {Customizing TabBar}, {Navigation Controls}, {Container Controls} */ diff --git a/src/templates/qquicktabbutton.cpp b/src/templates/qquicktabbutton.cpp index 00d4d8b4..a70dcbe1 100644 --- a/src/templates/qquicktabbutton.cpp +++ b/src/templates/qquicktabbutton.cpp @@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE \snippet qtlabscontrols-tabbutton.qml 1 + \labs + \sa TabBar, {Customizing TabButton}, {Navigation Controls} */ diff --git a/src/templates/qquicktextarea.cpp b/src/templates/qquicktextarea.cpp index 98fd7648..e83f8bf1 100644 --- a/src/templates/qquicktextarea.cpp +++ b/src/templates/qquicktextarea.cpp @@ -67,6 +67,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa TextField, {Customizing TextArea}, {Input Controls} */ diff --git a/src/templates/qquicktextfield.cpp b/src/templates/qquicktextfield.cpp index a8a6895e..782ff148 100644 --- a/src/templates/qquicktextfield.cpp +++ b/src/templates/qquicktextfield.cpp @@ -77,6 +77,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa TextArea, {Customizing TextField}, {Input Controls} */ diff --git a/src/templates/qquicktoolbar.cpp b/src/templates/qquicktoolbar.cpp index c20303e8..882834e3 100644 --- a/src/templates/qquicktoolbar.cpp +++ b/src/templates/qquicktoolbar.cpp @@ -86,6 +86,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa ApplicationWindow, ToolButton, {Customizing ToolBar}, {Container Controls} */ diff --git a/src/templates/qquicktoolbutton.cpp b/src/templates/qquicktoolbutton.cpp index 3505346c..775eedd1 100644 --- a/src/templates/qquicktoolbutton.cpp +++ b/src/templates/qquicktoolbutton.cpp @@ -73,6 +73,8 @@ QT_BEGIN_NAMESPACE } \endcode + \labs + \sa ToolBar, {Customizing ToolButton}, {Button Controls} */ diff --git a/src/templates/qquicktumbler.cpp b/src/templates/qquicktumbler.cpp index b1a64051..fcc443df 100644 --- a/src/templates/qquicktumbler.cpp +++ b/src/templates/qquicktumbler.cpp @@ -66,6 +66,8 @@ QT_BEGIN_NAMESPACE \image qtlabscontrols-tumbler-wrap.gif + \labs + \sa {Customizing Tumbler}, {Input Controls} */ |