diff options
author | J-P Nurmi <jpnurmi@theqtcompany.com> | 2016-02-26 13:52:56 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@theqtcompany.com> | 2016-03-23 12:46:11 +0000 |
commit | 0dd8a34f3b454d516f75e9b4be7691f934d2e849 (patch) | |
tree | 1b176eb891ce675e653093da645acd25253ff776 | |
parent | e346ed6f6db3fc0751c02b4b289f344d415cfdc9 (diff) |
Inherit QQuickDrawer from QQuickPopup
Change-Id: Icf71270e63aedd93ba975ab9743de68c3a54e849
Task-number: QTBUG-51007
Reviewed-by: J-P Nurmi <jpnurmi@theqtcompany.com>
-rw-r--r-- | examples/controls/gallery/gallery.qml | 99 | ||||
-rw-r--r-- | src/imports/controls/Drawer.qml | 40 | ||||
-rw-r--r-- | src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc | 7 | ||||
-rw-r--r-- | src/imports/controls/material/Drawer.qml | 38 | ||||
-rw-r--r-- | src/imports/controls/universal/Drawer.qml | 80 | ||||
-rw-r--r-- | src/imports/controls/universal/universal.pri | 1 | ||||
-rw-r--r-- | src/templates/qquickdrawer.cpp | 337 | ||||
-rw-r--r-- | src/templates/qquickdrawer_p.h | 29 | ||||
-rw-r--r-- | src/templates/qquickoverlay.cpp | 79 | ||||
-rw-r--r-- | src/templates/qquickpopup.cpp | 2 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_drawer.qml | 2 |
11 files changed, 396 insertions, 318 deletions
diff --git a/examples/controls/gallery/gallery.qml b/examples/controls/gallery/gallery.qml index 8a2c38d4..cb549475 100644 --- a/examples/controls/gallery/gallery.qml +++ b/examples/controls/gallery/gallery.qml @@ -111,65 +111,60 @@ ApplicationWindow { Drawer { id: drawer + width: Math.min(window.width, window.height) / 3 * 2 + height: window.height - Pane { - padding: 0 - width: Math.min(window.width, window.height) / 3 * 2 - height: window.height - - ListView { - id: listView - currentIndex: -1 - anchors.fill: parent + ListView { + id: listView + currentIndex: -1 + anchors.fill: parent - delegate: ItemDelegate { - width: parent.width - text: model.title - highlighted: ListView.isCurrentItem - onClicked: { - if (listView.currentIndex != index) { - listView.currentIndex = index - titleLabel.text = model.title - stackView.replace(model.source) - } - drawer.close() + delegate: ItemDelegate { + width: parent.width + text: model.title + highlighted: ListView.isCurrentItem + onClicked: { + if (listView.currentIndex != index) { + listView.currentIndex = index + titleLabel.text = model.title + stackView.replace(model.source) } + drawer.close() } + } - model: ListModel { - ListElement { title: "BusyIndicator"; source: "qrc:/pages/BusyIndicatorPage.qml" } - ListElement { title: "Button"; source: "qrc:/pages/ButtonPage.qml" } - ListElement { title: "CheckBox"; source: "qrc:/pages/CheckBoxPage.qml" } - ListElement { title: "ComboBox"; source: "qrc:/pages/ComboBoxPage.qml" } - ListElement { title: "Dial"; source: "qrc:/pages/DialPage.qml" } - ListElement { title: "Delegates"; source: "qrc:/pages/DelegatePage.qml" } - ListElement { title: "Drawer"; source: "qrc:/pages/DrawerPage.qml" } - ListElement { title: "Frame"; source: "qrc:/pages/FramePage.qml" } - ListElement { title: "GroupBox"; source: "qrc:/pages/GroupBoxPage.qml" } - ListElement { title: "Menu"; source: "qrc:/pages/MenuPage.qml" } - ListElement { title: "PageIndicator"; source: "qrc:/pages/PageIndicatorPage.qml" } - ListElement { title: "Popup"; source: "qrc:/pages/PopupPage.qml" } - ListElement { title: "ProgressBar"; source: "qrc:/pages/ProgressBarPage.qml" } - ListElement { title: "RadioButton"; source: "qrc:/pages/RadioButtonPage.qml" } - ListElement { title: "RangeSlider"; source: "qrc:/pages/RangeSliderPage.qml" } - ListElement { title: "ScrollBar"; source: "qrc:/pages/ScrollBarPage.qml" } - ListElement { title: "ScrollIndicator"; source: "qrc:/pages/ScrollIndicatorPage.qml" } - ListElement { title: "Slider"; source: "qrc:/pages/SliderPage.qml" } - ListElement { title: "SpinBox"; source: "qrc:/pages/SpinBoxPage.qml" } - ListElement { title: "StackView"; source: "qrc:/pages/StackViewPage.qml" } - ListElement { title: "SwipeView"; source: "qrc:/pages/SwipeViewPage.qml" } - ListElement { title: "Switch"; source: "qrc:/pages/SwitchPage.qml" } - ListElement { title: "TabBar"; source: "qrc:/pages/TabBarPage.qml" } - ListElement { title: "TextArea"; source: "qrc:/pages/TextAreaPage.qml" } - ListElement { title: "TextField"; source: "qrc:/pages/TextFieldPage.qml" } - ListElement { title: "ToolTip"; source: "qrc:/pages/ToolTipPage.qml" } - ListElement { title: "Tumbler"; source: "qrc:/pages/TumblerPage.qml" } - } - - ScrollIndicator.vertical: ScrollIndicator { } + model: ListModel { + ListElement { title: "BusyIndicator"; source: "qrc:/pages/BusyIndicatorPage.qml" } + ListElement { title: "Button"; source: "qrc:/pages/ButtonPage.qml" } + ListElement { title: "CheckBox"; source: "qrc:/pages/CheckBoxPage.qml" } + ListElement { title: "ComboBox"; source: "qrc:/pages/ComboBoxPage.qml" } + ListElement { title: "Dial"; source: "qrc:/pages/DialPage.qml" } + ListElement { title: "Delegates"; source: "qrc:/pages/DelegatePage.qml" } + ListElement { title: "Drawer"; source: "qrc:/pages/DrawerPage.qml" } + ListElement { title: "Frame"; source: "qrc:/pages/FramePage.qml" } + ListElement { title: "GroupBox"; source: "qrc:/pages/GroupBoxPage.qml" } + ListElement { title: "Menu"; source: "qrc:/pages/MenuPage.qml" } + ListElement { title: "PageIndicator"; source: "qrc:/pages/PageIndicatorPage.qml" } + ListElement { title: "Popup"; source: "qrc:/pages/PopupPage.qml" } + ListElement { title: "ProgressBar"; source: "qrc:/pages/ProgressBarPage.qml" } + ListElement { title: "RadioButton"; source: "qrc:/pages/RadioButtonPage.qml" } + ListElement { title: "RangeSlider"; source: "qrc:/pages/RangeSliderPage.qml" } + ListElement { title: "ScrollBar"; source: "qrc:/pages/ScrollBarPage.qml" } + ListElement { title: "ScrollIndicator"; source: "qrc:/pages/ScrollIndicatorPage.qml" } + ListElement { title: "Slider"; source: "qrc:/pages/SliderPage.qml" } + ListElement { title: "SpinBox"; source: "qrc:/pages/SpinBoxPage.qml" } + ListElement { title: "StackView"; source: "qrc:/pages/StackViewPage.qml" } + ListElement { title: "SwipeView"; source: "qrc:/pages/SwipeViewPage.qml" } + ListElement { title: "Switch"; source: "qrc:/pages/SwitchPage.qml" } + ListElement { title: "TabBar"; source: "qrc:/pages/TabBarPage.qml" } + ListElement { title: "TextArea"; source: "qrc:/pages/TextAreaPage.qml" } + ListElement { title: "TextField"; source: "qrc:/pages/TextFieldPage.qml" } + ListElement { title: "ToolTip"; source: "qrc:/pages/ToolTipPage.qml" } + ListElement { title: "Tumbler"; source: "qrc:/pages/TumblerPage.qml" } } + + ScrollIndicator.vertical: ScrollIndicator { } } - onClicked: close() } StackView { diff --git a/src/imports/controls/Drawer.qml b/src/imports/controls/Drawer.qml index 60abeb0c..bdab6376 100644 --- a/src/imports/controls/Drawer.qml +++ b/src/imports/controls/Drawer.qml @@ -35,18 +35,44 @@ ****************************************************************************/ import QtQuick 2.6 -import QtQuick.Window 2.2 import Qt.labs.templates 1.0 as T T.Drawer { id: control - parent: T.ApplicationWindow.overlay || Window.contentItem - width: parent ? parent.width : 0 // TODO: Window.width - height: parent ? parent.height : 0 // TODO: Window.height + implicitWidth: Math.max(background ? background.implicitWidth : 0, contentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, contentHeight + topPadding + bottomPadding) - // TODO: make this a proper transition - animation: SmoothedAnimation { - velocity: 5 + contentWidth: contentItem.implicitWidth || (contentChildren.length === 1 ? contentChildren[0].implicitWidth : 0) + contentHeight: contentItem.implicitHeight || (contentChildren.length === 1 ? contentChildren[0].implicitHeight : 0) + + topPadding: control.edge === Qt.BottomEdge + leftPadding: control.edge === Qt.RightEdge + rightPadding: control.edge === Qt.LeftEdge + bottomPadding: control.edge === Qt.TopEdge + + //! [enter] + enter: Transition { SmoothedAnimation { velocity: 5 } } + //! [enter] + + //! [exit] + exit: Transition { SmoothedAnimation { velocity: 5 } } + //! [exit] + + //! [contentItem] + contentItem: Item { } + //! [contentItem] + + //! [background] + background: Rectangle { + Rectangle { + readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge + width: horizontal ? 1 : parent.width + height: horizontal ? parent.height : 1 + color: "#353637" + x: control.edge === Qt.LeftEdge ? parent.width - 1 : 0 + y: control.edge === Qt.BottomEdge ? parent.height - 1 : 0 + } } + //! [background] } diff --git a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc index bc1e2504..57d310f0 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc @@ -148,17 +148,12 @@ \section1 Customizing Drawer Drawer can have a visual \l {Control::background}{background} - item. The navigation is implemented by the \l {Control::contentItem} - {content item}. + item. \section3 Background \snippet Drawer.qml background - \section3 Content item - - Drawer has no content item by default. - \section1 Customizing Frame diff --git a/src/imports/controls/material/Drawer.qml b/src/imports/controls/material/Drawer.qml index 133ea9c8..939beb5d 100644 --- a/src/imports/controls/material/Drawer.qml +++ b/src/imports/controls/material/Drawer.qml @@ -35,19 +35,43 @@ ****************************************************************************/ import QtQuick 2.6 -import QtQuick.Window 2.2 +import QtGraphicalEffects 1.0 import Qt.labs.templates 1.0 as T import Qt.labs.controls.material 1.0 T.Drawer { id: control - parent: T.ApplicationWindow.overlay || Window.contentItem - width: parent ? parent.width : 0 // TODO: Window.width - height: parent ? parent.height : 0 // TODO: Window.height + implicitWidth: Math.max(background ? background.implicitWidth : 0, contentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, contentHeight + topPadding + bottomPadding) - // TODO: make this a proper transition - animation: SmoothedAnimation { - velocity: 5 + contentWidth: contentItem.implicitWidth || (contentChildren.length === 1 ? contentChildren[0].implicitWidth : 0) + contentHeight: contentItem.implicitHeight || (contentChildren.length === 1 ? contentChildren[0].implicitHeight : 0) + + //! [enter] + enter: Transition { SmoothedAnimation { velocity: 5 } } + //! [enter] + + //! [exit] + exit: Transition { SmoothedAnimation { velocity: 5 } } + //! [exit] + + //! [contentItem] + contentItem: Item { } + //! [contentItem] + + //! [background] + background: Rectangle { + color: control.Material.dialogColor + + layer.enabled: control.position > 0 + layer.effect: DropShadow { + horizontalOffset: control.edge === Qt.LeftEdge ? 1 : control.edge === Qt.RightEdge ? -1 : 0 + verticalOffset: control.edge === Qt.TopEdge ? 1 : control.edge === Qt.BottomEdge ? -1 : 0 + color: control.Material.dropShadowColor + samples: 15 + spread: 0.5 + } } + //! [background] } diff --git a/src/imports/controls/universal/Drawer.qml b/src/imports/controls/universal/Drawer.qml new file mode 100644 index 00000000..57dac6d7 --- /dev/null +++ b/src/imports/controls/universal/Drawer.qml @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import Qt.labs.templates 1.0 as T +import Qt.labs.controls.universal 1.0 + +T.Drawer { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, contentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, contentHeight + topPadding + bottomPadding) + + contentWidth: contentItem.implicitWidth || (contentChildren.length === 1 ? contentChildren[0].implicitWidth : 0) + contentHeight: contentItem.implicitHeight || (contentChildren.length === 1 ? contentChildren[0].implicitHeight : 0) + + topPadding: control.edge === Qt.BottomEdge + leftPadding: control.edge === Qt.RightEdge + rightPadding: control.edge === Qt.LeftEdge + bottomPadding: control.edge === Qt.TopEdge + + //! [enter] + enter: Transition { SmoothedAnimation { velocity: 5 } } + //! [enter] + + //! [exit] + exit: Transition { SmoothedAnimation { velocity: 5 } } + //! [exit] + + //! [contentItem] + contentItem: Item { } + //! [contentItem] + + //! [background] + background: Rectangle { + color: control.Universal.chromeMediumLowColor + Rectangle { + readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge + width: horizontal ? 1 : parent.width + height: horizontal ? parent.height : 1 + color: control.Universal.chromeHighColor + x: control.edge === Qt.LeftEdge ? parent.width - 1 : 0 + y: control.edge === Qt.BottomEdge ? parent.height - 1 : 0 + } + } + //! [background] +} diff --git a/src/imports/controls/universal/universal.pri b/src/imports/controls/universal/universal.pri index a42589f7..6aa1baaa 100644 --- a/src/imports/controls/universal/universal.pri +++ b/src/imports/controls/universal/universal.pri @@ -5,6 +5,7 @@ QML_FILES += \ $$PWD/CheckBox.qml \ $$PWD/ComboBox.qml \ $$PWD/Dial.qml \ + $$PWD/Drawer.qml \ $$PWD/Frame.qml \ $$PWD/GroupBox.qml \ $$PWD/ItemDelegate.qml \ diff --git a/src/templates/qquickdrawer.cpp b/src/templates/qquickdrawer.cpp index 58fe2d87..bb1ad6ff 100644 --- a/src/templates/qquickdrawer.cpp +++ b/src/templates/qquickdrawer.cpp @@ -35,20 +35,21 @@ ****************************************************************************/ #include "qquickdrawer_p.h" +#include "qquickpopup_p_p.h" +#include "qquickvelocitycalculator_p_p.h" #include <QtGui/qstylehints.h> #include <QtGui/private/qguiapplication_p.h> #include <QtQuick/private/qquickwindow_p.h> #include <QtQuick/private/qquickanimation_p.h> +#include <QtQuick/private/qquicktransition_p.h> #include <QtQuick/private/qquickitemchangelistener_p.h> -#include <QtQuickTemplates/private/qquickcontrol_p_p.h> -#include <QtQuickTemplates/private/qquickvelocitycalculator_p_p.h> QT_BEGIN_NAMESPACE /*! \qmltype Drawer - \inherits Container + \inherits Popup \instantiates QQuickDrawer \inqmlmodule Qt.labs.controls \ingroup qtlabscontrols-navigation @@ -86,54 +87,68 @@ QT_BEGIN_NAMESPACE \sa SwipeView, {Customizing Drawer}, {Navigation Controls}, {Container Controls} */ -/*! - \qmlsignal Qt.labs.controls::Drawer::clicked() - - This signal is emitted when the drawer is clicked. -*/ - -class QQuickDrawerPrivate : public QQuickControlPrivate, public QQuickItemChangeListener +class QQuickDrawerPrivate : public QQuickPopupPrivate, public QQuickItemChangeListener { Q_DECLARE_PUBLIC(QQuickDrawer) public: - QQuickDrawerPrivate() : edge(Qt::LeftEdge), offset(0), position(0), - content(nullptr), animation(nullptr) { } + QQuickDrawerPrivate() : edge(Qt::LeftEdge), offset(0), position(0) { } + + qreal positionAt(const QPointF &point) const; + void reposition() override; - void updateContent(); bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); - void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) override; + void prepareEnterTransition(bool notify = true) override; + void prepareExitTransition() override; + void finalizeEnterTransition() override; + void finalizeExitTransition(bool hide = true) override; Qt::Edge edge; qreal offset; qreal position; QPointF pressPoint; QQuickVelocityCalculator velocityCalculator; - QQuickItem *content; - QQuickPropertyAnimation *animation; }; -void QQuickDrawerPrivate::updateContent() +qreal QQuickDrawerPrivate::positionAt(const QPointF &point) const +{ + Q_Q(const QQuickDrawer); + switch (edge) { + case Qt::TopEdge: + return point.y() / q->height(); + case Qt::LeftEdge: + return point.x() / q->width(); + case Qt::RightEdge: + return (q->width() - point.x()) / popupItem->width(); + case Qt::BottomEdge: + return (q->height() - point.y()) / popupItem->height(); + default: + return 0; + } +} + +void QQuickDrawerPrivate::reposition() { Q_Q(QQuickDrawer); - if (!content) + QQuickWindow *window = q->window(); + if (!window) return; switch (edge) { case Qt::LeftEdge: - content->setX((position - 1.0) * content->width()); + popupItem->setX((position - 1.0) * popupItem->width()); break; case Qt::RightEdge: - content->setX(q->width() + - position * content->width()); + popupItem->setX(window->width() - position * popupItem->width()); break; case Qt::TopEdge: - content->setY((position - 1.0) * content->height()); + popupItem->setY((position - 1.0) * popupItem->height()); break; case Qt::BottomEdge: - content->setY(q->height() + - position * content->height()); + popupItem->setY(window->height() - position * popupItem->height()); break; } } @@ -145,10 +160,13 @@ static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int th bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) { - Q_Q(QQuickDrawer); pressPoint = event->windowPos(); offset = 0; + QQuickWindow *window = item->window(); + if (!window) + return false; + if (qFuzzyIsNull(position)) { // only accept pressing at drag margins when fully closed switch (edge) { @@ -156,31 +174,34 @@ bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *e event->setAccepted(!dragOverThreshold(event->windowPos().x(), Qt::XAxis, event)); break; case Qt::RightEdge: - event->setAccepted(!dragOverThreshold(q->width() - event->windowPos().x(), Qt::XAxis, event)); + event->setAccepted(!dragOverThreshold(window->width() - event->windowPos().x(), Qt::XAxis, event)); break; case Qt::TopEdge: event->setAccepted(!dragOverThreshold(event->windowPos().y(), Qt::YAxis, event)); break; case Qt::BottomEdge: - event->setAccepted(!dragOverThreshold(q->height() - event->windowPos().y(), Qt::YAxis, event)); + event->setAccepted(!dragOverThreshold(window->height() - event->windowPos().y(), Qt::YAxis, event)); break; } } else { - event->accept(); + event->setAccepted(item->isAncestorOf(popupItem)); } velocityCalculator.startMeasuring(pressPoint, event->timestamp()); - return item == q; + return event->isAccepted(); } bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) { Q_Q(QQuickDrawer); - Q_UNUSED(item); + QQuickWindow *window = item->window(); + if (!window) + return false; + QPointF movePoint = event->windowPos(); - if (!q->keepMouseGrab()) { + if (!popupItem->keepMouseGrab()) { // Flickable uses a hard-coded threshold of 15 for flicking, and // QStyleHints::startDragDistance for dragging. Drawer uses a bit // larger threshold to avoid being too eager to steal touch (QTBUG-50045) @@ -191,86 +212,124 @@ bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *ev else overThreshold = dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, event, threshold); - if (window && overThreshold) { - QQuickItem *grabber = q->window()->mouseGrabberItem(); + if (overThreshold) { + QQuickItem *grabber = window->mouseGrabberItem(); if (!grabber || !grabber->keepMouseGrab()) { - q->grabMouse(); - q->setKeepMouseGrab(overThreshold); - offset = qMin<qreal>(0.0, q->positionAt(movePoint) - position); + popupItem->grabMouse(); + popupItem->setKeepMouseGrab(overThreshold); + offset = qMin<qreal>(0.0, positionAt(movePoint) - position); } } } - if (q->keepMouseGrab()) - q->setPosition(q->positionAt(movePoint) - offset); + if (popupItem->keepMouseGrab()) + q->setPosition(positionAt(movePoint) - offset); event->accept(); - return q->keepMouseGrab(); + return popupItem->keepMouseGrab(); } static const qreal openCloseVelocityThreshold = 300; bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event) { - Q_Q(QQuickDrawer); - bool wasGrabbed = q->keepMouseGrab(); + Q_UNUSED(item); + + bool wasGrabbed = popupItem->keepMouseGrab(); if (wasGrabbed) { velocityCalculator.stopMeasuring(event->pos(), event->timestamp()); const qreal velocity = velocityCalculator.velocity().x(); if (position > 0.7 || velocity > openCloseVelocityThreshold) { - q->open(); + transitionManager.transitionEnter(); } else if (position < 0.3 || velocity < -openCloseVelocityThreshold) { - q->close(); + transitionManager.transitionExit(); } else { switch (edge) { case Qt::LeftEdge: if (event->x() - pressPoint.x() > 0) - q->open(); + transitionManager.transitionEnter(); else - q->close(); + transitionManager.transitionExit(); break; case Qt::RightEdge: if (event->x() - pressPoint.x() < 0) - q->open(); + transitionManager.transitionEnter(); else - q->close(); + transitionManager.transitionExit(); break; case Qt::TopEdge: if (event->y() - pressPoint.y() > 0) - q->open(); + transitionManager.transitionEnter(); else - q->close(); + transitionManager.transitionExit(); break; case Qt::BottomEdge: if (event->y() - pressPoint.y() < 0) - q->open(); + transitionManager.transitionEnter(); else - q->close(); + transitionManager.transitionExit(); break; } } - q->setKeepMouseGrab(false); - } else { - if (item == q) - emit q->clicked(); + popupItem->setKeepMouseGrab(false); } pressPoint = QPoint(); event->accept(); return wasGrabbed; } -void QQuickDrawerPrivate::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) +static QList<QQuickStateAction> prepareTransition(QQuickDrawer *drawer, QQuickTransition *transition, qreal to) +{ + QList<QQuickStateAction> actions; + if (!transition) + return actions; + + qmlExecuteDeferred(transition); + + QQmlProperty defaultTarget(drawer, QLatin1String("position")); + QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations(); + int count = animations.count(&animations); + for (int i = 0; i < count; ++i) { + QQuickAbstractAnimation *anim = animations.at(&animations, i); + anim->setDefaultTarget(defaultTarget); + } + + actions << QQuickStateAction(drawer, QLatin1String("position"), to); + return actions; +} + +void QQuickDrawerPrivate::prepareEnterTransition(bool notify) +{ + Q_Q(QQuickDrawer); + enterActions = prepareTransition(q, enter, 1.0); + QQuickPopupPrivate::prepareEnterTransition(notify); +} + +void QQuickDrawerPrivate::prepareExitTransition() +{ + Q_Q(QQuickDrawer); + exitActions = prepareTransition(q, exit, 0.0); + QQuickPopupPrivate::prepareExitTransition(); +} + +void QQuickDrawerPrivate::finalizeEnterTransition() +{ + QQuickPopupPrivate::finalizeEnterTransition(); +} + +void QQuickDrawerPrivate::finalizeExitTransition(bool hide) { - updateContent(); + QQuickPopupPrivate::finalizeExitTransition(hide = false); } -QQuickDrawer::QQuickDrawer(QQuickItem *parent) : - QQuickControl(*(new QQuickDrawerPrivate), parent) +QQuickDrawer::QQuickDrawer(QObject *parent) : + QQuickPopup(*(new QQuickDrawerPrivate), parent) { - setZ(1); + setFocus(true); + setModal(true); setFiltersChildMouseEvents(true); - setAcceptedMouseButtons(Qt::LeftButton); + setClosePolicy(OnEscape | OnReleaseOutside); } /*! @@ -298,7 +357,7 @@ void QQuickDrawer::setEdge(Qt::Edge edge) d->edge = edge; if (isComponentComplete()) - d->updateContent(); + d->reposition(); emit edgeChanged(); } @@ -324,109 +383,10 @@ void QQuickDrawer::setPosition(qreal position) d->position = position; if (isComponentComplete()) - d->updateContent(); + d->reposition(); emit positionChanged(); } - -/*! - \qmlproperty Item Qt.labs.controls::Drawer::contentItem - - This property holds the content item that the drawer displays when opened. -*/ -QQuickItem *QQuickDrawer::contentItem() const -{ - Q_D(const QQuickDrawer); - return d->content; -} - -void QQuickDrawer::setContentItem(QQuickItem *item) -{ - Q_D(QQuickDrawer); - if (d->content == item) - return; - - if (d->content) { - QQuickItemPrivate::get(d->content)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); - delete d->content; - } - d->content = item; - if (item) { - item->setParentItem(this); - QQuickItemPrivate::get(item)->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange); - if (isComponentComplete()) - d->updateContent(); - } - emit contentItemChanged(); -} - -/*! - \qmlproperty Animation Qt.labs.controls::Drawer::animation - - This property holds the animation for the \l position property. It is used - to animate the drawer's movement. - - If no valid animation is set, the drawer's movement will not be animated. -*/ -QQuickPropertyAnimation *QQuickDrawer::animation() const -{ - Q_D(const QQuickDrawer); - return d->animation; -} - -void QQuickDrawer::setAnimation(QQuickPropertyAnimation *animation) -{ - Q_D(QQuickDrawer); - if (d->animation == animation) - return; - - delete d->animation; - d->animation = animation; - if (animation) { - animation->setTargetObject(this); - animation->setProperty(QStringLiteral("position")); - } - emit animationChanged(); -} - -/*! - \qmlmethod void Qt.labs.controls::Drawer::open() - - This method opens the drawer, animating the movement if a valid - \l animation has been set. -*/ -void QQuickDrawer::open() -{ - Q_D(QQuickDrawer); - if (d->animation) { - d->animation->stop(); - d->animation->setFrom(d->position); - d->animation->setTo(1.0); - d->animation->start(); - } else { - setPosition(1.0); - } -} - -/*! - \qmlmethod void Qt.labs.controls::Drawer::close() - - This method closes the drawer, animating the movement if a valid - \l animation has been set. -*/ -void QQuickDrawer::close() -{ - Q_D(QQuickDrawer); - if (d->animation) { - d->animation->stop(); - d->animation->setFrom(d->position); - d->animation->setTo(0.0); - d->animation->start(); - } else { - setPosition(0.0); - } -} - bool QQuickDrawer::childMouseEventFilter(QQuickItem *child, QEvent *event) { Q_D(QQuickDrawer); @@ -445,65 +405,56 @@ bool QQuickDrawer::childMouseEventFilter(QQuickItem *child, QEvent *event) void QQuickDrawer::mousePressEvent(QMouseEvent *event) { Q_D(QQuickDrawer); - QQuickControl::mousePressEvent(event); - d->handleMousePressEvent(this, event); + QQuickPopup::mousePressEvent(event); + d->handleMousePressEvent(d->popupItem, event); } void QQuickDrawer::mouseMoveEvent(QMouseEvent *event) { Q_D(QQuickDrawer); - QQuickControl::mouseMoveEvent(event); - d->handleMouseMoveEvent(this, event); + QQuickPopup::mouseMoveEvent(event); + d->handleMouseMoveEvent(d->popupItem, event); } void QQuickDrawer::mouseReleaseEvent(QMouseEvent *event) { Q_D(QQuickDrawer); - QQuickControl::mouseReleaseEvent(event); - d->handleMouseReleaseEvent(this, event); + QQuickPopup::mouseReleaseEvent(event); + d->handleMouseReleaseEvent(d->popupItem, event); } void QQuickDrawer::mouseUngrabEvent() { Q_D(QQuickDrawer); - QQuickControl::mouseUngrabEvent(); + QQuickPopup::mouseUngrabEvent(); d->pressPoint = QPoint(); d->velocityCalculator.reset(); } -void QQuickDrawer::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event) { Q_D(QQuickDrawer); - QQuickControl::geometryChanged(newGeometry, oldGeometry); - if (isComponentComplete()) - d->updateContent(); + switch (event->type()) { + case QEvent::MouseButtonPress: + d->tryClose(item, static_cast<QMouseEvent *>(event)); + return d->handleMousePressEvent(item, static_cast<QMouseEvent *>(event)); + case QEvent::MouseMove: + return d->handleMouseMoveEvent(item, static_cast<QMouseEvent *>(event)); + case QEvent::MouseButtonRelease: + d->tryClose(item, static_cast<QMouseEvent *>(event)); + return d->handleMouseReleaseEvent(item, static_cast<QMouseEvent *>(event)); + default: + return false; + } } void QQuickDrawer::componentComplete() { Q_D(QQuickDrawer); - QQuickControl::componentComplete(); - d->updateContent(); -} - -qreal QQuickDrawer::positionAt(const QPointF &point) const -{ - Q_D(const QQuickDrawer); - if (!d->content) - return 0.0; - - switch (d->edge) { - case Qt::TopEdge: - return point.y() / d->content->height(); - case Qt::LeftEdge: - return point.x() / d->content->width(); - case Qt::RightEdge: - return (width() - point.x()) / d->content->width(); - case Qt::BottomEdge: - return (height() - point.y()) / d->content->height(); - default: - return 0; - } + QQuickPopup::componentComplete(); + bool notify = false; + d->prepareEnterTransition(notify); + d->reposition(); } QT_END_NAMESPACE diff --git a/src/templates/qquickdrawer_p.h b/src/templates/qquickdrawer_p.h index ce9a3cb7..dfc4639a 100644 --- a/src/templates/qquickdrawer_p.h +++ b/src/templates/qquickdrawer_p.h @@ -48,25 +48,20 @@ // We mean it. // -#include <QtQuickTemplates/private/qquickcontrol_p.h> +#include <QtQuickTemplates/private/qquickpopup_p.h> QT_BEGIN_NAMESPACE -class QQuickPropertyAnimation; class QQuickDrawerPrivate; -class Q_QUICKTEMPLATES_EXPORT QQuickDrawer : public QQuickControl +class Q_QUICKTEMPLATES_EXPORT QQuickDrawer : public QQuickPopup { Q_OBJECT Q_PROPERTY(Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged FINAL) Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) - Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged FINAL) - // TODO: make this a proper transition - Q_PROPERTY(QQuickPropertyAnimation *animation READ animation WRITE setAnimation NOTIFY animationChanged FINAL) - Q_CLASSINFO("DefaultProperty", "contentItem") public: - explicit QQuickDrawer(QQuickItem *parent = nullptr); + explicit QQuickDrawer(QObject *parent = nullptr); Qt::Edge edge() const; void setEdge(Qt::Edge edge); @@ -74,22 +69,9 @@ public: qreal position() const; void setPosition(qreal position); - QQuickItem *contentItem() const; - void setContentItem(QQuickItem *item); - - QQuickPropertyAnimation *animation() const; - void setAnimation(QQuickPropertyAnimation *animation); - -public Q_SLOTS: - void open(); - void close(); - Q_SIGNALS: - void clicked(); void edgeChanged(); void positionChanged(); - void contentItemChanged(); - void animationChanged(); protected: bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; @@ -97,10 +79,9 @@ protected: void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseUngrabEvent() override; - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; - void componentComplete() override; + bool overlayEvent(QQuickItem *item, QEvent *event) override; - virtual qreal positionAt(const QPointF &point) const; + void componentComplete() override; private: Q_DISABLE_COPY(QQuickDrawer) diff --git a/src/templates/qquickoverlay.cpp b/src/templates/qquickoverlay.cpp index 8af5cb88..4977d08d 100644 --- a/src/templates/qquickoverlay.cpp +++ b/src/templates/qquickoverlay.cpp @@ -58,6 +58,7 @@ public: QQuickItem *background; QVector<QQuickDrawer *> drawers; QVector<QQuickPopup *> popups; + QPointer<QQuickPopup> mouseGrabberPopup; int modalPopups; }; @@ -93,7 +94,7 @@ void QQuickOverlayPrivate::drawerPositionChange() { Q_Q(QQuickOverlay); QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(q->sender()); - if (!background || !drawer || modalPopups > 0) + if (!background || !drawer || !drawer->isModal()) return; // call QQuickItem::setOpacity() directly to avoid triggering QML Behaviors @@ -155,18 +156,7 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) QQuickPopup *popup = nullptr; if (change == ItemChildAddedChange || change == ItemChildRemovedChange) { - QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(data.item); - if (drawer) { - if (change == ItemChildAddedChange) { - QObjectPrivate::connect(drawer, &QQuickDrawer::positionChanged, d, &QQuickOverlayPrivate::drawerPositionChange); - d->drawers.append(drawer); - } else { - QObjectPrivate::disconnect(drawer, &QQuickDrawer::positionChanged, d, &QQuickOverlayPrivate::drawerPositionChange); - d->drawers.removeOne(drawer); - } - } else { - popup = qobject_cast<QQuickPopup *>(data.item->parent()); - } + popup = qobject_cast<QQuickPopup *>(data.item->parent()); setVisible(!childItems().isEmpty()); } if (!popup) @@ -174,18 +164,32 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) if (change == ItemChildAddedChange) { d->popups.append(popup); - if (popup->isModal()) - ++d->modalPopups; - QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); - QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); + QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup); + if (drawer) { + QObjectPrivate::connect(drawer, &QQuickDrawer::positionChanged, d, &QQuickOverlayPrivate::drawerPositionChange); + d->drawers.append(drawer); + } else { + if (popup->isModal()) + ++d->modalPopups; + + QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); + QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); + } } else if (change == ItemChildRemovedChange) { d->popups.removeOne(popup); - if (popup->isModal()) - --d->modalPopups; - QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); - QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); + QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup); + if (drawer) { + QObjectPrivate::disconnect(drawer, &QQuickDrawer::positionChanged, d, &QQuickOverlayPrivate::drawerPositionChange); + d->drawers.removeOne(drawer); + } else { + if (popup->isModal()) + --d->modalPopups; + + QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); + QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); + } } } @@ -203,19 +207,42 @@ bool QQuickOverlay::event(QEvent *event) switch (event->type()) { case QEvent::MouseButtonPress: emit pressed(); + for (auto it = d->popups.crbegin(), end = d->popups.crend(); it != end; ++it) { + if ((*it)->overlayEvent(this, event)) { + d->mouseGrabberPopup = *it; + return true; + } + } + break; + case QEvent::MouseMove: + if (d->mouseGrabberPopup) { + if (d->mouseGrabberPopup->overlayEvent(this, event)) + return true; + } else { + for (auto it = d->popups.crbegin(), end = d->popups.crend(); it != end; ++it) { + if ((*it)->overlayEvent(this, event)) + return true; + } + } break; case QEvent::MouseButtonRelease: emit released(); + if (d->mouseGrabberPopup) { + QQuickPopup *grabber = d->mouseGrabberPopup; + d->mouseGrabberPopup = nullptr; + if (grabber->overlayEvent(this, event)) + return true; + } else { + for (auto it = d->popups.crbegin(), end = d->popups.crend(); it != end; ++it) { + if ((*it)->overlayEvent(this, event)) + return true; + } + } break; default: break; } - for (auto it = d->popups.crbegin(), end = d->popups.crend(); it != end; ++it) { - if ((*it)->overlayEvent(this, event)) - return true; - } - return QQuickItem::event(event); } diff --git a/src/templates/qquickpopup.cpp b/src/templates/qquickpopup.cpp index 5589b095..2caa91b2 100644 --- a/src/templates/qquickpopup.cpp +++ b/src/templates/qquickpopup.cpp @@ -181,7 +181,7 @@ void QQuickPopupPrivate::prepareEnterTransition(bool notify) if (notify) emit q->aboutToShow(); - visible = true; + visible = notify; popupItem->setVisible(true); positioner.setParentItem(parentItem); emit q->visibleChanged(); diff --git a/tests/auto/controls/data/tst_drawer.qml b/tests/auto/controls/data/tst_drawer.qml index b6ea297c..6306de17 100644 --- a/tests/auto/controls/data/tst_drawer.qml +++ b/tests/auto/controls/data/tst_drawer.qml @@ -57,10 +57,8 @@ TestCase { function test_defaults() { var control = drawer.createObject(testCase) - verify(!control.contentItem) compare(control.edge, Qt.LeftEdge) compare(control.position, 0.0) - verify(control.animation) control.destroy() } |