aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@theqtcompany.com>2016-02-26 13:52:56 +0100
committerJ-P Nurmi <jpnurmi@theqtcompany.com>2016-03-23 12:46:11 +0000
commit0dd8a34f3b454d516f75e9b4be7691f934d2e849 (patch)
tree1b176eb891ce675e653093da645acd25253ff776
parente346ed6f6db3fc0751c02b4b289f344d415cfdc9 (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.qml99
-rw-r--r--src/imports/controls/Drawer.qml40
-rw-r--r--src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc7
-rw-r--r--src/imports/controls/material/Drawer.qml38
-rw-r--r--src/imports/controls/universal/Drawer.qml80
-rw-r--r--src/imports/controls/universal/universal.pri1
-rw-r--r--src/templates/qquickdrawer.cpp337
-rw-r--r--src/templates/qquickdrawer_p.h29
-rw-r--r--src/templates/qquickoverlay.cpp79
-rw-r--r--src/templates/qquickpopup.cpp2
-rw-r--r--tests/auto/controls/data/tst_drawer.qml2
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()
}