From e83cbaddbfec2aaae157ef0223f1e8d38a3d37bc Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 14 Sep 2016 13:22:46 +0200 Subject: Drawer: fix flickering on touch release Change-Id: I9a8b46fd796652822760f70d0c59db54214337b1 Task-number: QTBUG-55995 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index be4d624d..0f5e5824 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -309,6 +309,12 @@ bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *ev Q_Q(QQuickDrawer); Q_UNUSED(item); + // Don't react to synthesized mouse move events at INF,INF coordinates. + // QQuickWindowPrivate::translateTouchToMouse() uses them to clear hover + // on touch release (QTBUG-55995). + if (qIsInf(event->screenPos().x()) || qIsInf(event->screenPos().y())) + return true; + const QPointF movePoint = event->windowPos(); if (grabMouse(event)) { -- cgit v1.2.3 From c886facd990acf207f3164662601222babc8dde2 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 15 Sep 2016 07:38:53 +0200 Subject: QQuickControl: clear the hovered state when hidden Task-number: QTBUG-56007 Change-Id: I6433e0ebc9570b1e9e6e149ef7f631ea6786f672 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickcontrol.cpp | 4 ++++ tests/auto/controls/data/tst_control.qml | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index 642e2e72..dc8ad4c9 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -397,6 +397,10 @@ void QQuickControl::itemChange(QQuickItem::ItemChange change, const QQuickItem:: Q_D(QQuickControl); QQuickItem::itemChange(change, value); switch (change) { + case ItemVisibleHasChanged: + if (!value.boolValue) + setHovered(false); + break; case ItemParentHasChanged: if (value.item) { d->resolveFont(); diff --git a/tests/auto/controls/data/tst_control.qml b/tests/auto/controls/data/tst_control.qml index 601b7f8f..4b7a60dc 100644 --- a/tests/auto/controls/data/tst_control.qml +++ b/tests/auto/controls/data/tst_control.qml @@ -880,6 +880,12 @@ TestCase { mouseMove(control, -10, -10) compare(control.hovered, false) + mouseMove(control, control.width / 2, control.height / 2) + compare(control.hovered, true) + + control.visible = false + compare(control.hovered, false) + control.destroy() } -- cgit v1.2.3 From 03967915ea171e7e53201734f158654b0c315f59 Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Wed, 7 Sep 2016 16:40:06 +0200 Subject: qquickapplicationwindow.cpp: fix typo in property doc Change-Id: Ia9b2da125a0beb41e47f1b9bb37e7c6fb8435e2e Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickapplicationwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index 28095aa6..2afdf15c 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -436,7 +436,7 @@ QQuickItem *QQuickApplicationWindow::contentItem() const The difference between \l Window::activeFocusItem and ApplicationWindow::activeFocusControl is that the former may point to a building block of a control, whereas the latter points to the enclosing control. For example, when SpinBox has focus, activeFocusItem points to - the editor and acticeFocusControl to the SpinBox itself. + the editor and activeFocusControl to the SpinBox itself. \sa Window::activeFocusItem */ -- cgit v1.2.3 From ffdb00d903ca343ac08ffb44535956d6fad9ae49 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 15 Sep 2016 11:57:21 +0200 Subject: List .qdoc files and snippets in OTHER_FILES Change-Id: Ic33bc3d69771dab79ccaf307b00ed0f840b9e8b2 Reviewed-by: Venugopal Shivashankar --- src/imports/controls/controls.pro | 3 +-- src/imports/controls/doc/doc.pri | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 src/imports/controls/doc/doc.pri diff --git a/src/imports/controls/controls.pro b/src/imports/controls/controls.pro index 282c3217..15c07cf0 100644 --- a/src/imports/controls/controls.pro +++ b/src/imports/controls/controls.pro @@ -7,8 +7,6 @@ QT_PRIVATE += core-private gui-private qml-private quick-private quicktemplates2 DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII -QMAKE_DOCS = $$PWD/doc/qtquickcontrols2.qdocconf - OTHER_FILES += \ qmldir @@ -20,6 +18,7 @@ RESOURCES += \ include(controls.pri) !static: include(designer/designer.pri) +include(doc/doc.pri) qtquickcompiler { qmlfiles.prefix = /qt-project.org/imports/QtQuick/Controls.2 diff --git a/src/imports/controls/doc/doc.pri b/src/imports/controls/doc/doc.pri new file mode 100644 index 00000000..8eaccbed --- /dev/null +++ b/src/imports/controls/doc/doc.pri @@ -0,0 +1,7 @@ +QMAKE_DOCS = $$PWD/qtquickcontrols2.qdocconf + +OTHER_FILES += \ + $$files($$PWD/snippets/*.qml) \ + $$files($$PWD/src/*.qdoc) \ + $$files($$PWD/src/calendar/*.qdoc) \ + $$files($$PWD/src/templates/*.qdoc) -- cgit v1.2.3 From ba48e1e6ea375af6eb1e0310395c00e3a41770b4 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Sep 2016 09:19:47 +0200 Subject: Frame: link to contentItem in detailed description Change-Id: Ifa936562b25ae99f3d912ecea356373a018b5660 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickframe.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickframe.cpp b/src/quicktemplates2/qquickframe.cpp index 2f2a5497..bcc387c1 100644 --- a/src/quicktemplates2/qquickframe.cpp +++ b/src/quicktemplates2/qquickframe.cpp @@ -54,8 +54,8 @@ QT_BEGIN_NAMESPACE or a \l ColumnLayout. Items declared as children of a Frame are automatically parented to the - Frame's contentItem. Items created dynamically need to be explicitly - parented to the contentItem. + Frame's \l {Control::}{contentItem}. Items created dynamically need to be + explicitly parented to the contentItem. If only a single item is used within a Frame, it will resize to fit the implicit size of its contained item. This makes it particularly suitable -- cgit v1.2.3 From 2b0db3a4809e6316114ec65bd55fa80ddefe97c5 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Sep 2016 10:06:43 +0200 Subject: GroupBox: fix documentation review findings Change-Id: I1663fed5d4639d35f93029b64e64f3cd14a8138d Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickgroupbox.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/quicktemplates2/qquickgroupbox.cpp b/src/quicktemplates2/qquickgroupbox.cpp index 45fe406f..27c325ef 100644 --- a/src/quicktemplates2/qquickgroupbox.cpp +++ b/src/quicktemplates2/qquickgroupbox.cpp @@ -48,10 +48,10 @@ QT_BEGIN_NAMESPACE \inqmlmodule QtQuick.Controls \since 5.7 \ingroup qtquickcontrols2-containers - \brief A frame with a logical group of controls. + \brief A logical group of controls within a titled visual frame. GroupBox is used to layout a logical group of controls together, within - a titled visual frame. GroupBox does not provide a layout of its own, but + a \l {title}{titled} visual frame. GroupBox does not provide a layout of its own, but requires you to position its contents, for instance by creating a \l RowLayout or a \l ColumnLayout. @@ -75,8 +75,8 @@ QT_BEGIN_NAMESPACE \image qtquickcontrols2-groupbox-checkable.png It is a common pattern to enable or disable the groupbox's children when - its checkbox is toggled on or off, but it is the application that decides - on the behavior of the groupbox. + its checkbox is toggled on or off, but it is up to the application to decide + on the behavior of the checkbox. \snippet qtquickcontrols2-groupbox-checkable.qml 1 @@ -101,6 +101,9 @@ QQuickGroupBox::QQuickGroupBox(QQuickItem *parent) : \qmlproperty string QtQuick.Controls::GroupBox::title This property holds the title. + + The title is typically displayed above the groupbox to + summarize its contents. */ QString QQuickGroupBox::title() const { -- cgit v1.2.3 From 8bac9a45693b14ce6f1f39d67f57c2327a0adb4e Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Sep 2016 11:13:11 +0200 Subject: CheckDelegate: expand detailed description Mention the API that is inherited and the difference between it and CheckBox. Change-Id: I931fa410e90b686d0ac27a2fd5945ef9e8b6f949 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickcheckdelegate.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/quicktemplates2/qquickcheckdelegate.cpp b/src/quicktemplates2/qquickcheckdelegate.cpp index 09be5d60..249aaa95 100644 --- a/src/quicktemplates2/qquickcheckdelegate.cpp +++ b/src/quicktemplates2/qquickcheckdelegate.cpp @@ -54,9 +54,14 @@ QT_BEGIN_NAMESPACE CheckDelegate presents an item delegate that can be toggled on (checked) or off (unchecked). Check delegates are typically used to select one or more - options from a set of options. - - The state of the check delegate can be set with the + options from a set of options in a list. For smaller sets of options, or + for options that need to be uniquely identifiable, consider using + \l CheckBox instead. + + CheckDelegate inherits its API from \l ItemDelegate, which is inherited + from AbstractButton. For instance, you can set \l {AbstractButton::text}{text}, + and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton + API. The state of the check delegate can be set with the \l {AbstractButton::}{checked} property. In addition to the checked and unchecked states, there is a third state: @@ -75,7 +80,7 @@ QT_BEGIN_NAMESPACE } \endcode - \sa {Customizing CheckDelegate}, {Delegate Controls} + \sa {Customizing CheckDelegate}, {Delegate Controls}, CheckBox */ class QQuickCheckDelegatePrivate : public QQuickItemDelegatePrivate -- cgit v1.2.3 From 3c6ea8948b67d758dc777b044df127d5514ecc08 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Sep 2016 11:29:23 +0200 Subject: CheckBox: expand detailed description Mention that the API is inherited from AbstractButton, and how it's different from CheckDelegate. Change-Id: I3de58b57ee3a00194312ab6bff1aa43ce58f3199 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickcheckbox.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickcheckbox.cpp b/src/quicktemplates2/qquickcheckbox.cpp index 1daf69dc..a777c2b4 100644 --- a/src/quicktemplates2/qquickcheckbox.cpp +++ b/src/quicktemplates2/qquickcheckbox.cpp @@ -52,9 +52,11 @@ QT_BEGIN_NAMESPACE CheckBox presents an option button that can be toggled on (checked) or off (unchecked). Check boxes are typically used to select one or more - options from a set of options. + options from a set of options. For larger sets of options, such as those + in a list, consider using \l CheckDelegate instead. - The state of the checkbox can be set with the \l {AbstractButton::}{checked} property. + CheckBox inherits its API from \l AbstractButton. For instance, the + state of the checkbox can be set with the \l {AbstractButton::}{checked} property. In addition to the checked and unchecked states, there is a third state: partially checked. The partially checked state can be enabled using the -- cgit v1.2.3 From 0365837e6658829b287a5196d3e0ebb1389a8c38 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Sep 2016 12:06:57 +0200 Subject: Button: fix autoRepeat and checkable documentation review findings Change-Id: Ic8c90c284863077681ee1d143a366138cd550825 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickbutton.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickbutton.cpp b/src/quicktemplates2/qquickbutton.cpp index a51e2210..901f730d 100644 --- a/src/quicktemplates2/qquickbutton.cpp +++ b/src/quicktemplates2/qquickbutton.cpp @@ -116,6 +116,17 @@ QQuickButton::QQuickButton(QQuickItem *parent) : \qmlproperty bool QtQuick.Controls::Button::checkable This property holds whether the button is checkable. + + A checkable button toggles between checked (on) and unchecked (off) when + the user clicks on it or presses the space bar while the button has active + focus. + + Setting \l {AbstractButton::}{checked} to \c true forces this property to + \c true. + + The default value is \c false. + + \sa CheckBox, Switch */ void QQuickButton::checkableChange() @@ -126,8 +137,10 @@ void QQuickButton::checkableChange() /*! \qmlproperty bool QtQuick.Controls::Button::autoRepeat - This property holds whether the button repeats pressed(), released() - and clicked() signals while the button is pressed and held down. + This property holds whether the button repeats + \l {AbstractButton::}{pressed()}, \l {AbstractButton::}{released()} + and \l {AbstractButton::}{clicked()} signals while the button is pressed + and held down. The default value is \c false. */ -- cgit v1.2.3 From 0f6c236f47087ea96e587a9f03d18996551f8764 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Sep 2016 08:34:27 +0200 Subject: Container: rephrase paragraph about declaring children The more common use case is static declaration of children. Change-Id: Ie1c7b44ae9e738e02f89957b27f6111a1e798736 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickcontainer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickcontainer.cpp b/src/quicktemplates2/qquickcontainer.cpp index 43fda437..34e198fc 100644 --- a/src/quicktemplates2/qquickcontainer.cpp +++ b/src/quicktemplates2/qquickcontainer.cpp @@ -55,9 +55,11 @@ QT_BEGIN_NAMESPACE \section2 Using Containers - Container provides an API to \l {addItem}{add}, \l {insertItem}{insert}, + Typically, items are statically declared as children of Container, but it + is also possible to \l {addItem}{add}, \l {insertItem}{insert}, \l {moveItem}{move} and \l {removeItem}{remove} items dynamically. The - items in a container can be accessed using \l itemAt() or \l contentChildren. + items in a container can be accessed using \l itemAt() or + \l contentChildren. Most containers have the concept of a "current" item. The current item is specified via the \l currentIndex property, and can be accessed using the -- cgit v1.2.3 From 60bbe9d5157c50a35f891105819aaf851eb136bc Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Sep 2016 08:20:00 +0200 Subject: Dial: clarify the documentation for some properties - Document the range of the angle property - Fix handle's property type - Explain stepSize more thoroughly Change-Id: I72ce8b493b3faf49d7f155ac802109bd9bdb4089 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickdial.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index 3b096255..48d02faa 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -300,6 +300,8 @@ qreal QQuickDial::position() const Like the \l position property, angle is continuously updated while the handle is dragged. + The range is from \c -140 degrees to \c 140 degrees. + \sa position */ qreal QQuickDial::angle() const @@ -311,7 +313,18 @@ qreal QQuickDial::angle() const /*! \qmlproperty real QtQuick.Controls::Dial::stepSize - This property holds the step size. The default value is \c 0.0. + This property holds the step size. + + The step size determines the amount by which the dial's value + is increased and decreased when interacted with via the keyboard. + For example, a step size of \c 0.2, will result in the dial's + value increasing and decreasing in increments of \c 0.2. + + The step size is only respected for touch and mouse interaction + when \l snapMode is set to a value other than \c Dial.NoSnap. + + The default value is \c 0.0, which results in an effective step + size of \c 0.1 for keyboard interaction. \sa snapMode, increase(), decrease() */ @@ -460,7 +473,7 @@ void QQuickDial::decrease() } /*! - \qmlproperty component QtQuick.Controls::Dial::handle + \qmlproperty Item QtQuick.Controls::Dial::handle This property holds the handle of the dial. -- cgit v1.2.3 From 541a7a8e785476e2e93f88f770715f25ce7e6dc8 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 15 Sep 2016 06:46:54 +0200 Subject: Drawer: fix drag to close from the outside on touch Set mouseGrabberPopup in QQuickOverlay::childMouseEventFilter() the same way it is set in QQuickOverlay::mousePressEvent() to ensure that the consequent mouse move events are routed to the appropriate popup. This worked with "genuine" mouse move events that were caught by the same child mouse event filter and that way routed to the appropriate popup, but not with "synthesized" mouse move events that are caught by QQuickOverlay::mousePressEvent() instead. Change-Id: Ic59afd85e55c13ebec482bc4dc534accd1f92b2c Task-number: QTBUG-56010 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 6 +++- tests/auto/drawer/BLACKLIST | 2 ++ tests/auto/drawer/tst_drawer.cpp | 58 +++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/auto/drawer/BLACKLIST diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index c6e34ee2..a1fdffb3 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -404,7 +404,11 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) switch (event->type()) { case QEvent::MouseButtonPress: emit pressed(); - return popup->overlayEvent(item, event); + if (popup->overlayEvent(item, event)) { + d->mouseGrabberPopup = popup; + return true; + } + break; case QEvent::MouseMove: return popup->overlayEvent(item, event); case QEvent::MouseButtonRelease: diff --git a/tests/auto/drawer/BLACKLIST b/tests/auto/drawer/BLACKLIST new file mode 100644 index 00000000..1b06b49c --- /dev/null +++ b/tests/auto/drawer/BLACKLIST @@ -0,0 +1,2 @@ +[touch] +windows diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index 8b02e95c..3a02e9a9 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -40,7 +40,10 @@ #include "../shared/visualtestutil.h" #include +#include #include +#include +#include #include #include #include @@ -74,6 +77,9 @@ private slots: void wheel(); void multiple(); + + void touch_data(); + void touch(); }; void tst_Drawer::visible_data() @@ -615,6 +621,58 @@ void tst_Drawer::multiple() QCOMPARE(leftDrawer->position(), 0.0); } +void tst_Drawer::touch_data() +{ + QTest::addColumn("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + +void tst_Drawer::touch() +{ + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value(); + QVERIFY(drawer); + + struct TouchDeviceDeleter + { + static inline void cleanup(QTouchDevice *device) + { + QWindowSystemInterface::unregisterTouchDevice(device); + delete device; + } + }; + + QScopedPointer device(new QTouchDevice); + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device.data()); + + // drag to open + QTest::touchEvent(window, device.data()).press(0, QPoint(0, 100)); + QTest::touchEvent(window, device.data()).move(0, QPoint(100, 100)); + QTRY_COMPARE(drawer->position(), 0.5); + QTest::touchEvent(window, device.data()).release(0, QPoint(100, 100)); + QTRY_COMPARE(drawer->position(), 1.0); + + // drag to close + QTest::touchEvent(window, device.data()).press(0, QPoint(300, 100)); + QTest::touchEvent(window, device.data()).move(0, QPoint(300 - drawer->dragMargin(), 100)); + for (int x = 300; x > 100; x -= 10) { + QTest::touchEvent(window, device.data()).move(0, QPoint(x, 100)); + QQuickWindowPrivate::get(window)->flushDelayedTouchEvent(); + } + QTest::touchEvent(window, device.data()).move(0, QPoint(100, 100)); + QTRY_COMPARE(drawer->position(), 0.5); + QTest::touchEvent(window, device.data()).release(0, QPoint(100, 100)); + QTRY_COMPARE(drawer->position(), 0.0); +} + QTEST_MAIN(tst_Drawer) #include "tst_drawer.moc" -- cgit v1.2.3 From fbe806c544a45c83f091109e04fab5d86620183f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 15 Sep 2016 16:50:16 +0200 Subject: Fix Popup to respect explicit size [ChangeLog][Controls][Popup] Fixed to respect explicitly set width and height. Task-number: QTBUG-56025 Change-Id: I7c8b0dcf59459a313c4c52eda44de45f1ab648ea Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickpopup.cpp | 12 ++++++--- src/quicktemplates2/qquickpopup_p_p.h | 2 ++ tests/auto/controls/data/tst_popup.qml | 48 ++++++++++++++++++++++++++++++---- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 0eab6ad5..d3280040 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -125,6 +125,8 @@ QQuickPopupPrivate::QQuickPopupPrivate() , hasDim(false) , visible(false) , complete(false) + , hasWidth(false) + , hasHeight(false) , hasTopMargin(false) , hasLeftMargin(false) , hasRightMargin(false) @@ -587,7 +589,7 @@ void QQuickPopupPrivate::reposition() bool widthAdjusted = false; bool heightAdjusted = false; - QRectF rect(x, y, iw > 0 ? iw : w, ih > 0 ? ih : h); + QRectF rect(x, y, !hasWidth && iw > 0 ? iw : w, !hasHeight && ih > 0 ? ih : h); if (parentItem) { rect = parentItem->mapRectToScene(rect); @@ -681,9 +683,9 @@ void QQuickPopupPrivate::reposition() emit q->yChanged(); } - if (widthAdjusted && rect.width() > 0) + if (!hasWidth && widthAdjusted && rect.width() > 0) popupItem->setWidth(rect.width()); - if (heightAdjusted && rect.height() > 0) + if (!hasHeight && heightAdjusted && rect.height() > 0) popupItem->setHeight(rect.height()); } @@ -907,12 +909,14 @@ qreal QQuickPopup::width() const void QQuickPopup::setWidth(qreal width) { Q_D(QQuickPopup); + d->hasWidth = true; d->popupItem->setWidth(width); } void QQuickPopup::resetWidth() { Q_D(QQuickPopup); + d->hasWidth = false; d->popupItem->resetWidth(); } @@ -930,12 +934,14 @@ qreal QQuickPopup::height() const void QQuickPopup::setHeight(qreal height) { Q_D(QQuickPopup); + d->hasHeight = true; d->popupItem->setHeight(height); } void QQuickPopup::resetHeight() { Q_D(QQuickPopup); + d->hasHeight = false; d->popupItem->resetHeight(); } diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h index b828edc1..745a7f83 100644 --- a/src/quicktemplates2/qquickpopup_p_p.h +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -183,6 +183,8 @@ public: bool hasDim; bool visible; bool complete; + bool hasWidth; + bool hasHeight; bool hasTopMargin; bool hasLeftMargin; bool hasRightMargin; diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index e714a7d0..919bfffc 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -940,14 +940,52 @@ TestCase { var control = popupControl.createObject(testCase) verify(control) - control.width = 200 - control.height = 200 - control.open() waitForRendering(control.contentItem) - compare(control.width, 200) - compare(control.height, 200) + // implicit size of the content + control.contentItem.implicitWidth = 10 + compare(control.implicitWidth, 10 + control.leftPadding + control.rightPadding) + compare(control.width, control.implicitWidth) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.contentItem.implicitHeight = 20 + compare(control.implicitHeight, 20 + control.topPadding + control.bottomPadding) + compare(control.height, control.implicitHeight) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) + + // implicit size of the popup + control.implicitWidth = 30 + compare(control.implicitWidth, 30) + compare(control.width, 30) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.implicitHeight = 40 + compare(control.implicitHeight, 40) + compare(control.height, 40) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) + + // set explicit size + control.width = 50 + compare(control.implicitWidth, 30) + compare(control.width, 50) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.height = 60 + compare(control.implicitHeight, 40) + compare(control.height, 60) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) + + // reset explicit size + control.width = undefined + compare(control.implicitWidth, 30) + compare(control.width, 30) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.height = undefined + compare(control.implicitHeight, 40) + compare(control.height, 40) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) control.destroy() } -- cgit v1.2.3 From 935974e174d87f9bf10a56d14bb73ade726d827a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 19 Sep 2016 15:19:40 +0200 Subject: Fix Switch to stay pressed as appropriate Switch is a special type of button that should stay pressed (similarly to Slider) even if the finger slips outside the bounds of the control. It was doing that only when dragged from the handle, not when dragged from the background. Change-Id: I462c66cfe2e67fc3c95215ffeafe3e5771174418 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickabstractbutton.cpp | 6 +++--- src/quicktemplates2/qquickabstractbutton_p_p.h | 1 + src/quicktemplates2/qquickswitch.cpp | 2 ++ tests/auto/controls/data/tst_switch.qml | 23 +++++++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index 220ec102..96adbf9a 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -105,7 +105,7 @@ static const int AUTO_REPEAT_INTERVAL = 100; */ QQuickAbstractButtonPrivate::QQuickAbstractButtonPrivate() : - down(false), explicitDown(false), pressed(false), checked(false), checkable(false), + down(false), explicitDown(false), pressed(false), keepPressed(false), checked(false), checkable(false), autoExclusive(false), autoRepeat(false), wasHeld(false), holdTimer(0), delayTimer(0), repeatTimer(0), repeatButton(Qt::NoButton), indicator(nullptr), group(nullptr) { @@ -525,7 +525,7 @@ void QQuickAbstractButton::mouseMoveEvent(QMouseEvent *event) { Q_D(QQuickAbstractButton); QQuickControl::mouseMoveEvent(event); - setPressed(contains(event->pos())); + setPressed(d->keepPressed || contains(event->pos())); if (d->autoRepeat) d->stopPressRepeat(); @@ -540,7 +540,7 @@ void QQuickAbstractButton::mouseReleaseEvent(QMouseEvent *event) bool wasPressed = d->pressed; setPressed(false); - if (contains(event->pos())) + if (d->keepPressed || contains(event->pos())) nextCheckState(); if (wasPressed) { diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h index e690bbd0..8138a61d 100644 --- a/src/quicktemplates2/qquickabstractbutton_p_p.h +++ b/src/quicktemplates2/qquickabstractbutton_p_p.h @@ -82,6 +82,7 @@ public: bool down; bool explicitDown; bool pressed; + bool keepPressed; bool checked; bool checkable; bool autoExclusive; diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index 37ae53f0..7941bf69 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -184,6 +184,8 @@ bool QQuickSwitchPrivate::handleMouseUngrabEvent(QQuickItem *child) QQuickSwitch::QQuickSwitch(QQuickItem *parent) : QQuickAbstractButton(*(new QQuickSwitchPrivate), parent) { + Q_D(QQuickSwitch); + d->keepPressed = true; setCheckable(true); setFiltersChildMouseEvents(true); QObjectPrivate::connect(this, &QQuickAbstractButton::checkedChanged, d_func(), &QQuickSwitchPrivate::updatePosition); diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index ba41015f..1b77ff42 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -95,6 +95,29 @@ TestCase { control.destroy() } + function test_pressed_data() { + return [ + { tag: "indicator", x: 15 }, + { tag: "background", x: 5 } + ] + } + + function test_pressed(data) { + var control = swtch.createObject(testCase, {padding: 10}) + verify(control) + + // stays pressed when dragged outside + compare(control.pressed, false) + mousePress(control, data.x, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + mouseMove(control, -1, control.height / 2) + compare(control.pressed, true) + mouseRelease(control, -1, control.height / 2, Qt.LeftButton) + compare(control.pressed, false) + + control.destroy() + } + function test_mouse() { var control = swtch.createObject(testCase) verify(control) -- cgit v1.2.3 From e5079c1828dd0fe2e90347f20da40da033fbec5a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 19 Sep 2016 15:39:29 +0200 Subject: QQuickSwitch: utilize checkStateSet() QQuickAbstractButton::checkStateSet() did not exist when QQuickSwitch was originally implemented. QQuickSwitch no longer has to establish a signal-slot connection, but can just override the virtual to update the position when the checked state changes. Change-Id: Ic18f13bcd7b0fe9fe657c41094b4d1db5cbb2e5a Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickswitch.cpp | 14 ++++++-------- src/quicktemplates2/qquickswitch_p.h | 2 ++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index 7941bf69..beb9a764 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -90,7 +90,6 @@ class QQuickSwitchPrivate : public QQuickAbstractButtonPrivate public: QQuickSwitchPrivate() : position(0) { } - void updatePosition(); qreal positionAt(const QPoint &point) const; bool handleMousePressEvent(QQuickItem *child, QMouseEvent *event); @@ -102,12 +101,6 @@ public: QPoint pressPoint; }; -void QQuickSwitchPrivate::updatePosition() -{ - Q_Q(QQuickSwitch); - q->setPosition(checked ? 1.0 : 0.0); -} - qreal QQuickSwitchPrivate::positionAt(const QPoint &point) const { Q_Q(const QQuickSwitch); @@ -188,7 +181,6 @@ QQuickSwitch::QQuickSwitch(QQuickItem *parent) : d->keepPressed = true; setCheckable(true); setFiltersChildMouseEvents(true); - QObjectPrivate::connect(this, &QQuickAbstractButton::checkedChanged, d_func(), &QQuickSwitchPrivate::updatePosition); } /*! @@ -255,4 +247,10 @@ bool QQuickSwitch::childMouseEventFilter(QQuickItem *child, QEvent *event) return false; } +void QQuickSwitch::checkStateSet() +{ + Q_D(QQuickSwitch); + setPosition(d->checked ? 1.0 : 0.0); +} + QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickswitch_p.h b/src/quicktemplates2/qquickswitch_p.h index fa92e9f3..bfbcceed 100644 --- a/src/quicktemplates2/qquickswitch_p.h +++ b/src/quicktemplates2/qquickswitch_p.h @@ -76,6 +76,8 @@ protected: void mirrorChange() override; bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + void checkStateSet() override; + private: Q_DISABLE_COPY(QQuickSwitch) Q_DECLARE_PRIVATE(QQuickSwitch) -- cgit v1.2.3 From 6ed4918f131ff235bcab3efe849f5b67406ef350 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 19 Sep 2016 15:43:36 +0200 Subject: QQuickSwitch: fix event handling Switch implemented custom event handling for the indicator, and used QQuickAbstractButton's event handling for the background. This lead to inconsistent signals depending on whether interacting with the handle or the background. This change gets rid of the child mouse event filter for the indicator and makes QQuickSwitch fully utilize the base class event handlers. Change-Id: I773e2eb939cbbf4bc9086cdf2b34e876597ea08e Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickswitch.cpp | 123 +++++++++----------------------- src/quicktemplates2/qquickswitch_p.h | 6 +- tests/auto/controls/data/tst_switch.qml | 70 ++++++++++++++++++ 3 files changed, 108 insertions(+), 91 deletions(-) diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index beb9a764..27043c8b 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -90,97 +90,28 @@ class QQuickSwitchPrivate : public QQuickAbstractButtonPrivate public: QQuickSwitchPrivate() : position(0) { } - qreal positionAt(const QPoint &point) const; - - bool handleMousePressEvent(QQuickItem *child, QMouseEvent *event); - bool handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event); - bool handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event); - bool handleMouseUngrabEvent(QQuickItem *child); + qreal positionAt(const QPointF &point) const; qreal position; - QPoint pressPoint; }; -qreal QQuickSwitchPrivate::positionAt(const QPoint &point) const +qreal QQuickSwitchPrivate::positionAt(const QPointF &point) const { Q_Q(const QQuickSwitch); - qreal pos = point.x() / indicator->width(); + qreal pos = 0.0; + if (indicator) + pos = indicator->mapFromItem(q, point).x() / indicator->width(); if (q->isMirrored()) return 1.0 - pos; return pos; } -bool QQuickSwitchPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent *event) -{ - Q_Q(QQuickSwitch); - Q_UNUSED(child); - if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && !QGuiApplication::styleHints()->setFocusOnTouchRelease()) - q->forceActiveFocus(Qt::MouseFocusReason); - - pressPoint = event->pos(); - q->setPressed(true); - emit q->pressed(); - event->accept(); - return true; -} - -bool QQuickSwitchPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event) -{ - Q_Q(QQuickSwitch); - if (!child->keepMouseGrab()) - child->setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().x() - pressPoint.x(), Qt::XAxis, event)); - if (child->keepMouseGrab()) { - q->setPosition(positionAt(event->pos())); - event->accept(); - } - return true; -} - -bool QQuickSwitchPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event) -{ - Q_Q(QQuickSwitch); - if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && QGuiApplication::styleHints()->setFocusOnTouchRelease()) - q->forceActiveFocus(Qt::MouseFocusReason); - - pressPoint = QPoint(); - q->setPressed(false); - if (child->keepMouseGrab()) { - bool wasChecked = checked; - q->setChecked(position > 0.5); - q->setPosition(checked ? 1.0 : 0.0); - child->setKeepMouseGrab(false); - if (wasChecked != checked) { - emit q->released(); - emit q->clicked(); - } - event->accept(); - } else { - q->toggle(); - emit q->released(); - emit q->clicked(); - event->accept(); - } - return true; -} - -bool QQuickSwitchPrivate::handleMouseUngrabEvent(QQuickItem *child) -{ - Q_Q(QQuickSwitch); - Q_UNUSED(child); - pressPoint = QPoint(); - q->setChecked(position > 0.5); - q->setPosition(checked ? 1.0 : 0.0); - q->setPressed(false); - return true; -} - QQuickSwitch::QQuickSwitch(QQuickItem *parent) : QQuickAbstractButton(*(new QQuickSwitchPrivate), parent) { Q_D(QQuickSwitch); d->keepPressed = true; setCheckable(true); - setFiltersChildMouseEvents(true); } /*! @@ -221,30 +152,42 @@ qreal QQuickSwitch::visualPosition() const return d->position; } +void QQuickSwitch::mousePressEvent(QMouseEvent *event) +{ + QQuickAbstractButton::mousePressEvent(event); +} + +void QQuickSwitch::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickSwitch); + QQuickAbstractButton::mouseMoveEvent(event); + + const QPointF movePoint = event->localPos(); + if (!keepMouseGrab()) + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event)); + if (keepMouseGrab()) + setPosition(d->positionAt(movePoint)); +} + +void QQuickSwitch::mouseReleaseEvent(QMouseEvent *event) +{ + QQuickAbstractButton::mouseReleaseEvent(event); + setKeepMouseGrab(false); +} + void QQuickSwitch::mirrorChange() { QQuickAbstractButton::mirrorChange(); emit visualPositionChanged(); } -bool QQuickSwitch::childMouseEventFilter(QQuickItem *child, QEvent *event) +void QQuickSwitch::nextCheckState() { Q_D(QQuickSwitch); - if (child == indicator()) { - switch (event->type()) { - case QEvent::MouseButtonPress: - return d->handleMousePressEvent(child, static_cast(event)); - case QEvent::MouseMove: - return d->handleMouseMoveEvent(child, static_cast(event)); - case QEvent::MouseButtonRelease: - return d->handleMouseReleaseEvent(child, static_cast(event)); - case QEvent::UngrabMouse: - return d->handleMouseUngrabEvent(child); - default: - return false; - } - } - return false; + if (keepMouseGrab()) + setChecked(d->position > 0.5); + else + QQuickAbstractButton::nextCheckState(); } void QQuickSwitch::checkStateSet() diff --git a/src/quicktemplates2/qquickswitch_p.h b/src/quicktemplates2/qquickswitch_p.h index bfbcceed..27a065b4 100644 --- a/src/quicktemplates2/qquickswitch_p.h +++ b/src/quicktemplates2/qquickswitch_p.h @@ -73,9 +73,13 @@ Q_SIGNALS: void visualPositionChanged(); protected: + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mirrorChange() override; - bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + void nextCheckState() override; void checkStateSet() override; private: diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index 1b77ff42..f854526c 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -200,6 +200,76 @@ TestCase { control.destroy() } + function test_drag() { + var control = swtch.createObject(testCase, {leftPadding: 100, rightPadding: 100}) + verify(control) + + var spy = signalSequenceSpy.createObject(control, {target: control}) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + + // press-drag-release inside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control.indicator, 0) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control.indicator, control.width) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control.indicator, control.indicator.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, 0) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.leftPadding) + compare(control.position, 0.0) + compare(control.checked, true) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + control.destroy() + } + function test_keys() { var control = swtch.createObject(testCase) verify(control) -- cgit v1.2.3 From b3983692680a91023dc5f22608b4e84b46fae883 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 19 Sep 2016 16:39:41 +0200 Subject: QQuickSwitchDelegate: make the handle draggable Sync the implementation with QQuickSwitch to make it behave exactly the same way. Change-Id: I59d08f68f87d8776e4012da880ac57a99950dfe8 Task-number: QTBUG-55686 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickswitchdelegate.cpp | 57 ++++++-- src/quicktemplates2/qquickswitchdelegate_p.h | 7 + tests/auto/controls/data/tst_switchdelegate.qml | 182 ++++++++++++++++++++++++ 3 files changed, 234 insertions(+), 12 deletions(-) diff --git a/src/quicktemplates2/qquickswitchdelegate.cpp b/src/quicktemplates2/qquickswitchdelegate.cpp index fbdae418..e22d163a 100644 --- a/src/quicktemplates2/qquickswitchdelegate.cpp +++ b/src/quicktemplates2/qquickswitchdelegate.cpp @@ -80,22 +80,17 @@ public: { } - void updatePosition(); - qreal positionAt(const QPoint &point) const; + qreal positionAt(const QPointF &point) const; qreal position; }; -void QQuickSwitchDelegatePrivate::updatePosition() -{ - Q_Q(QQuickSwitchDelegate); - q->setPosition(checked ? 1.0 : 0.0); -} - -qreal QQuickSwitchDelegatePrivate::positionAt(const QPoint &point) const +qreal QQuickSwitchDelegatePrivate::positionAt(const QPointF &point) const { Q_Q(const QQuickSwitchDelegate); - qreal pos = point.x() / indicator->width(); + qreal pos = 0.0; + if (indicator) + pos = indicator->mapFromItem(q, point).x() / indicator->width(); if (q->isMirrored()) return 1.0 - pos; return pos; @@ -104,9 +99,9 @@ qreal QQuickSwitchDelegatePrivate::positionAt(const QPoint &point) const QQuickSwitchDelegate::QQuickSwitchDelegate(QQuickItem *parent) : QQuickItemDelegate(*(new QQuickSwitchDelegatePrivate), parent) { + Q_D(QQuickSwitchDelegate); + d->keepPressed = true; setCheckable(true); - - QObjectPrivate::connect(this, &QQuickAbstractButton::checkedChanged, d_func(), &QQuickSwitchDelegatePrivate::updatePosition); } /*! @@ -147,6 +142,29 @@ qreal QQuickSwitchDelegate::visualPosition() const return d->position; } +void QQuickSwitchDelegate::mousePressEvent(QMouseEvent *event) +{ + QQuickItemDelegate::mousePressEvent(event); +} + +void QQuickSwitchDelegate::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickSwitchDelegate); + QQuickItemDelegate::mouseMoveEvent(event); + + const QPointF movePoint = event->localPos(); + if (!keepMouseGrab()) + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event)); + if (keepMouseGrab()) + setPosition(d->positionAt(movePoint)); +} + +void QQuickSwitchDelegate::mouseReleaseEvent(QMouseEvent *event) +{ + QQuickItemDelegate::mouseReleaseEvent(event); + setKeepMouseGrab(false); +} + QFont QQuickSwitchDelegate::defaultFont() const { return QQuickControlPrivate::themeFont(QPlatformTheme::ListViewFont); @@ -158,4 +176,19 @@ void QQuickSwitchDelegate::mirrorChange() emit visualPositionChanged(); } +void QQuickSwitchDelegate::nextCheckState() +{ + Q_D(QQuickSwitchDelegate); + if (keepMouseGrab()) + setChecked(d->position > 0.5); + else + QQuickItemDelegate::nextCheckState(); +} + +void QQuickSwitchDelegate::checkStateSet() +{ + Q_D(QQuickSwitchDelegate); + setPosition(d->checked ? 1.0 : 0.0); +} + QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickswitchdelegate_p.h b/src/quicktemplates2/qquickswitchdelegate_p.h index 5126f643..c0cc21ac 100644 --- a/src/quicktemplates2/qquickswitchdelegate_p.h +++ b/src/quicktemplates2/qquickswitchdelegate_p.h @@ -73,9 +73,16 @@ Q_SIGNALS: void visualPositionChanged(); protected: + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + QFont defaultFont() const override; void mirrorChange() override; + void nextCheckState() override; + void checkStateSet() override; + private: Q_DISABLE_COPY(QQuickSwitchDelegate) Q_DECLARE_PRIVATE(QQuickSwitchDelegate) diff --git a/tests/auto/controls/data/tst_switchdelegate.qml b/tests/auto/controls/data/tst_switchdelegate.qml index 231736c6..6d23a403 100644 --- a/tests/auto/controls/data/tst_switchdelegate.qml +++ b/tests/auto/controls/data/tst_switchdelegate.qml @@ -55,6 +55,13 @@ TestCase { SwitchDelegate {} } + Component { + id: signalSequenceSpy + SignalSequenceSpy { + signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged"] + } + } + // TODO: data-fy tst_checkbox (rename to tst_check?) so we don't duplicate its tests here? function test_defaults() { @@ -83,4 +90,179 @@ TestCase { compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset); control.destroy(); } + + function test_pressed_data() { + return [ + { tag: "indicator", x: 15 }, + { tag: "background", x: 5 } + ] + } + + function test_pressed(data) { + var control = switchDelegate.createObject(testCase, {padding: 10}) + verify(control) + + // stays pressed when dragged outside + compare(control.pressed, false) + mousePress(control, data.x, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + mouseMove(control, -1, control.height / 2) + compare(control.pressed, true) + mouseRelease(control, -1, control.height / 2, Qt.LeftButton) + compare(control.pressed, false) + + control.destroy() + } + + function test_mouse() { + var control = switchDelegate.createObject(testCase) + verify(control) + + // check + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // uncheck + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // release on the right + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + mouseMove(control, control.width * 2, control.height / 2, 0, Qt.LeftButton) + compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width * 2, control.height / 2, Qt.LeftButton) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // release on the left + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + mouseMove(control, -control.width, control.height / 2, 0, Qt.LeftButton) + compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, -control.width, control.height / 2, Qt.LeftButton) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // right button + spy.expectedSequence = [] + mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) + compare(control.pressed, false) + verify(spy.success) + mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + control.destroy() + } + + function test_drag() { + var control = switchDelegate.createObject(testCase, {leftPadding: 100, rightPadding: 100}) + verify(control) + + var spy = signalSequenceSpy.createObject(control, {target: control}) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + + // press-drag-release inside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control.indicator, 0) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control.indicator, control.width) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control.indicator, control.indicator.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, 0) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.leftPadding) + compare(control.position, 0.0) + compare(control.checked, true) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + control.destroy() + } } -- cgit v1.2.3 From 7b9c4db132d03a24b63d1fb9f3d85c82b63089db Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 20 Sep 2016 10:02:44 +0200 Subject: Switch/Delegate: improve dragging behavior Don't start dragging the handle unless the initial press was at the indicator, or the drag has reached the indicator area. This prevents unnatural jumps when dragging far outside the indicator. Change-Id: I2b31b319a347ab489f2de5c044e42d908827b425 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickswitch.cpp | 12 +++++++-- src/quicktemplates2/qquickswitchdelegate.cpp | 12 +++++++-- tests/auto/controls/data/tst_switch.qml | 34 +++++++++++++++++++++++++ tests/auto/controls/data/tst_switchdelegate.qml | 34 +++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index 27043c8b..a7d17e86 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -163,8 +163,16 @@ void QQuickSwitch::mouseMoveEvent(QMouseEvent *event) QQuickAbstractButton::mouseMoveEvent(event); const QPointF movePoint = event->localPos(); - if (!keepMouseGrab()) - setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event)); + if (!keepMouseGrab()) { + // don't start dragging the handle unless the initial press was at the indicator, + // or the drag has reached the indicator area. this prevents unnatural jumps when + // dragging far outside the indicator. + const qreal pressPos = d->positionAt(d->pressPoint); + const qreal movePos = d->positionAt(movePoint); + if ((pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0)) + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event)); + } + if (keepMouseGrab()) setPosition(d->positionAt(movePoint)); } diff --git a/src/quicktemplates2/qquickswitchdelegate.cpp b/src/quicktemplates2/qquickswitchdelegate.cpp index e22d163a..62b677e5 100644 --- a/src/quicktemplates2/qquickswitchdelegate.cpp +++ b/src/quicktemplates2/qquickswitchdelegate.cpp @@ -153,8 +153,16 @@ void QQuickSwitchDelegate::mouseMoveEvent(QMouseEvent *event) QQuickItemDelegate::mouseMoveEvent(event); const QPointF movePoint = event->localPos(); - if (!keepMouseGrab()) - setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event)); + if (!keepMouseGrab()) { + // don't start dragging the handle unless the initial press was at the indicator, + // or the drag has reached the indicator area. this prevents unnatural jumps when + // dragging far outside the indicator. + const qreal pressPos = d->positionAt(d->pressPoint); + const qreal movePos = d->positionAt(movePoint); + if ((pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0)) + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event)); + } + if (keepMouseGrab()) setPosition(d->positionAt(movePoint)); } diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index f854526c..93773e0d 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -267,6 +267,40 @@ TestCase { compare(control.pressed, false) verify(spy.success) + // press-drag-release from and to outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + control.destroy() } diff --git a/tests/auto/controls/data/tst_switchdelegate.qml b/tests/auto/controls/data/tst_switchdelegate.qml index 6d23a403..8bc0e4c3 100644 --- a/tests/auto/controls/data/tst_switchdelegate.qml +++ b/tests/auto/controls/data/tst_switchdelegate.qml @@ -263,6 +263,40 @@ TestCase { compare(control.pressed, false) verify(spy.success) + // press-drag-release from and to outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + control.destroy() } } -- cgit v1.2.3 From 6462c39e0ef19e8d84c895e83c99133dc59e850c Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 20 Sep 2016 10:17:05 +0200 Subject: Control: link to "Control Layout" section in relevant places Change-Id: I82ec57bca3dffc19400f90eba13985df4be103de Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickcontrol.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index dc8ad4c9..4d8609f7 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -464,7 +464,7 @@ void QQuickControl::resetFont() This property holds the width available after deducting horizontal padding. - \sa padding, leftPadding, rightPadding + \sa {Control Layout}, padding, leftPadding, rightPadding */ qreal QQuickControl::availableWidth() const { @@ -477,7 +477,7 @@ qreal QQuickControl::availableWidth() const This property holds the height available after deducting vertical padding. - \sa padding, topPadding, bottomPadding + \sa {Control Layout}, padding, topPadding, bottomPadding */ qreal QQuickControl::availableHeight() const { @@ -489,7 +489,7 @@ qreal QQuickControl::availableHeight() const This property holds the default padding. - \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding + \sa {Control Layout}, availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding */ qreal QQuickControl::padding() const { @@ -531,7 +531,7 @@ void QQuickControl::resetPadding() This property holds the top padding. - \sa padding, bottomPadding, availableHeight + \sa {Control Layout}, padding, bottomPadding, availableHeight */ qreal QQuickControl::topPadding() const { @@ -558,7 +558,7 @@ void QQuickControl::resetTopPadding() This property holds the left padding. - \sa padding, rightPadding, availableWidth + \sa {Control Layout}, padding, rightPadding, availableWidth */ qreal QQuickControl::leftPadding() const { @@ -585,7 +585,7 @@ void QQuickControl::resetLeftPadding() This property holds the right padding. - \sa padding, leftPadding, availableWidth + \sa {Control Layout}, padding, leftPadding, availableWidth */ qreal QQuickControl::rightPadding() const { @@ -612,7 +612,7 @@ void QQuickControl::resetRightPadding() This property holds the bottom padding. - \sa padding, topPadding, availableHeight + \sa {Control Layout}, padding, topPadding, availableHeight */ qreal QQuickControl::bottomPadding() const { -- cgit v1.2.3 From 462419c33116df0418f17549860112e416522cfa Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 20 Sep 2016 08:18:37 +0200 Subject: Control: explain diagram and make it a linkable section Change-Id: I6e0d2349bdc909e61048356d76dc877e33fad5ff Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- .../doc/images/qtquickcontrols2-control.png | Bin 34588 -> 22234 bytes .../doc/images/qtquickcontrols2-control.svg | 392 +++++++++++++++++++++ src/quicktemplates2/qquickcontrol.cpp | 22 ++ 3 files changed, 414 insertions(+) create mode 100644 src/imports/controls/doc/images/qtquickcontrols2-control.svg diff --git a/src/imports/controls/doc/images/qtquickcontrols2-control.png b/src/imports/controls/doc/images/qtquickcontrols2-control.png index 28fcb742..26babc9f 100644 Binary files a/src/imports/controls/doc/images/qtquickcontrols2-control.png and b/src/imports/controls/doc/images/qtquickcontrols2-control.png differ diff --git a/src/imports/controls/doc/images/qtquickcontrols2-control.svg b/src/imports/controls/doc/images/qtquickcontrols2-control.svg new file mode 100644 index 00000000..b0ffae7c --- /dev/null +++ b/src/imports/controls/doc/images/qtquickcontrols2-control.svg @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Background + Content item + + Available height Available width Width + + Height Control Bottom padding Top padding Right padding Left padding + diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index 4d8609f7..e294055c 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -70,8 +70,26 @@ QT_BEGIN_NAMESPACE events from the window system, and paints a representation of itself on the screen. + \section1 Control Layout + + The following diagram illustrates the layout of a typical control: + \image qtquickcontrols2-control.png + The \l {Item::}{implicitWidth} and \l {Item::}{implicitHeight} of a control + are typically based on the implicit sizes of the background and the content + item plus any \l {Control::}{padding}. These properties determine how large + the control will be when no explicit \l {Item::}{width} or + \l {Item::}{height} is specified. + + The \l {Control::}{background} item fills the entire width and height of the + control, unless an explicit size has been given for it. + + The geometry of the \l {Control::}{contentItem} is determined by the + padding. + + \section1 Event Handling + All controls, except non-interactive indicators, do not let clicks and touches through to items below them. For example, if \l Pane is used as the \l {ApplicationWindow::}{header} or \l {ApplicationWindow::}{footer} of @@ -946,6 +964,8 @@ void QQuickControl::setWheelEnabled(bool enabled) \note If the background item has no explicit size specified, it automatically follows the control's size. In most cases, there is no need to specify width or height for a background item. + + \sa {Control Layout} */ QQuickItem *QQuickControl::background() const { @@ -977,6 +997,8 @@ void QQuickControl::setBackground(QQuickItem *background) This property holds the visual content item. \note The content item is automatically resized inside the \l padding of the control. + + \sa {Control Layout} */ QQuickItem *QQuickControl::contentItem() const { -- cgit v1.2.3 From 85230f227f38d56572ad4650dda9fcce3942f86d Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 20 Sep 2016 10:51:43 +0200 Subject: Control: elaborate on the documentation for various properties Change-Id: I48f1a9cf56e6b92ef34e954259e64d090bb445ca Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickcontrol.cpp | 51 ++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index e294055c..8c5c75d2 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -480,7 +480,8 @@ void QQuickControl::resetFont() \qmlproperty real QtQuick.Controls::Control::availableWidth \readonly - This property holds the width available after deducting horizontal padding. + This property holds the width available to the \l contentItem after + deducting horizontal padding from the \l {Item::}{width} of the control. \sa {Control Layout}, padding, leftPadding, rightPadding */ @@ -493,7 +494,8 @@ qreal QQuickControl::availableWidth() const \qmlproperty real QtQuick.Controls::Control::availableHeight \readonly - This property holds the height available after deducting vertical padding. + This property holds the height available to the \l contentItem after + deducting vertical padding from the \l {Item::}{height} of the control. \sa {Control Layout}, padding, topPadding, bottomPadding */ @@ -507,6 +509,18 @@ qreal QQuickControl::availableHeight() const This property holds the default padding. + Padding adds a space between each edge of the content item and the + background item, effectively controlling the size of the content item. To + specify a padding value for a specific edge of the control, set its + relevant property: + + \list + \li \l {Control::}{leftPadding} + \li \l {Control::}{rightPadding} + \li \l {Control::}{topPadding} + \li \l {Control::}{bottomPadding} + \endlist + \sa {Control Layout}, availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding */ qreal QQuickControl::padding() const @@ -656,6 +670,12 @@ void QQuickControl::resetBottomPadding() \qmlproperty real QtQuick.Controls::Control::spacing This property holds the spacing. + + Spacing is useful for controls that have multiple or repetitive building + blocks. For example, some styles use spacing to determine the distance + between the text and indicator of \l CheckBox. Spacing is not enforced by + Control, so each style may interpret it differently, and some may ignore it + altogether. */ qreal QQuickControl::spacing() const { @@ -788,9 +808,11 @@ void QQuickControlPrivate::updateLocaleRecur(QQuickItem *item, const QLocale &l) This property holds whether the control is mirrored. This property is provided for convenience. A control is considered mirrored - when its visual layout direction is right-to-left. + when its visual layout direction is right-to-left; that is, when using a + right-to-left locale or when \l {LayoutMirroring::enabled}{LayoutMirroring.enabled} + is \c true. - \sa locale, {LayoutMirroring}{LayoutMirroring} + \sa locale, {LayoutMirroring}{LayoutMirroring}, {Right-to-left User Interfaces} */ bool QQuickControl::isMirrored() const { @@ -939,6 +961,10 @@ void QQuickControl::setHoverEnabled(bool enabled) \qmlproperty bool QtQuick.Controls::Control::wheelEnabled This property determines whether the control handles wheel events. The default value is \c false. + + \note Care must be taken when enabling wheel events for controls within scrollable items such + as \l Flickable, as the control will consume the events and hence interrupt scrolling of the + Flickable. */ bool QQuickControl::isWheelEnabled() const { @@ -965,6 +991,12 @@ void QQuickControl::setWheelEnabled(bool enabled) follows the control's size. In most cases, there is no need to specify width or height for a background item. + \note Most controls use the implicit size of the background item to calculate + the implicit size of the control itself. If you replace the background item + with a custom one, you should also consider providing a sensible implicit + size for it (unless it is an item like \l Image which has its own implicit + size). + \sa {Control Layout} */ QQuickItem *QQuickControl::background() const @@ -996,9 +1028,16 @@ void QQuickControl::setBackground(QQuickItem *background) This property holds the visual content item. - \note The content item is automatically resized inside the \l padding of the control. + \note The content item is automatically resized to fit within the + \l padding of the control. - \sa {Control Layout} + \note Most controls use the implicit size of the content item to calculate + the implicit size of the control itself. If you replace the content item + with a custom one, you should also consider providing a sensible implicit + size for it (unless it is an item like \l Text which has its own implicit + size). + + \sa {Control Layout}, padding */ QQuickItem *QQuickControl::contentItem() const { -- cgit v1.2.3 From 29668bf3ebef803d67aa4e0bff8cc784149996a9 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 20 Sep 2016 15:48:37 +0200 Subject: Move resizeOverlay() to QQuickPopupPrivate This is a preparation step for making drawers movable. Drawer must be later able to resize the overlay to fit the area of the window that is covered by the drawer. For example, if the Drawer is below the header, it can resize the overlay so that it won't be on top of the header. Change-Id: I2cfd025a31f3a517575f3dbf9b972dcd6957715c Task-number: QTBUG-53168 Task-number: QTBUG-55360 Task-number: QTBUG-53609 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 14 ++------------ src/quicktemplates2/qquickoverlay_p_p.h | 1 - src/quicktemplates2/qquickpopup.cpp | 10 ++++++++++ src/quicktemplates2/qquickpopup_p_p.h | 1 + 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index a1fdffb3..dbbc82bb 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -113,7 +113,7 @@ void QQuickOverlayPrivate::createOverlay(QQuickPopup *popup) QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); if (!p->dimmer) p->dimmer = createDimmer(popup->isModal() ? modal : modeless, popup, q); - resizeOverlay(popup); + p->resizeOverlay(); } void QQuickOverlayPrivate::destroyOverlay(QQuickPopup *popup) @@ -126,16 +126,6 @@ void QQuickOverlayPrivate::destroyOverlay(QQuickPopup *popup) } } -void QQuickOverlayPrivate::resizeOverlay(QQuickPopup *popup) -{ - Q_Q(QQuickOverlay); - QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup); - if (p->dimmer) { - p->dimmer->setWidth(q->width()); - p->dimmer->setHeight(q->height()); - } -} - void QQuickOverlayPrivate::toggleOverlay() { Q_Q(QQuickOverlay); @@ -320,7 +310,7 @@ void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &old Q_D(QQuickOverlay); QQuickItem::geometryChanged(newGeometry, oldGeometry); for (QQuickPopup *popup : qAsConst(d->allPopups)) - d->resizeOverlay(popup); + QQuickPopupPrivate::get(popup)->resizeOverlay(); } void QQuickOverlay::mousePressEvent(QMouseEvent *event) diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h index 6dc2853c..6201908e 100644 --- a/src/quicktemplates2/qquickoverlay_p_p.h +++ b/src/quicktemplates2/qquickoverlay_p_p.h @@ -78,7 +78,6 @@ public: void createOverlay(QQuickPopup *popup); void destroyOverlay(QQuickPopup *popup); - void resizeOverlay(QQuickPopup *popup); void toggleOverlay(); QVector stackingOrderPopups() const; diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index d3280040..8c0e5990 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -689,6 +689,16 @@ void QQuickPopupPrivate::reposition() popupItem->setHeight(rect.height()); } +void QQuickPopupPrivate::resizeOverlay() +{ + if (!dimmer) + return; + + qreal w = window ? window->width() : 0; + qreal h = window ? window->height() : 0; + dimmer->setSize(QSizeF(w, h)); +} + void QQuickPopupPositioner::removeAncestorListeners(QQuickItem *item) { if (item == m_parentItem) diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h index 745a7f83..321adaf5 100644 --- a/src/quicktemplates2/qquickpopup_p_p.h +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -157,6 +157,7 @@ public: void init(); bool tryClose(QQuickItem *item, QMouseEvent *event); virtual void reposition(); + virtual void resizeOverlay(); virtual bool prepareEnterTransition(); virtual bool prepareExitTransition(); -- cgit v1.2.3 From 8a4af9e87704f7b8ed269114d3ab75430bd61998 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 20 Sep 2016 16:23:57 +0200 Subject: QQuickPopup: fix negative margins The documentation states: A popup with negative margins is not pushed within the bounds of the enclosing window. Therefore QQuickPopupPrivate::reposition() must not subtract negative margins to calculate the available bounds. Change-Id: I626772970bf3d5d9eefbb13811ea1003a85bcf0b Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickpopup.cpp | 5 ++++- tests/auto/controls/data/tst_popup.qml | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 8c0e5990..2a48473a 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -595,7 +595,10 @@ void QQuickPopupPrivate::reposition() if (window) { const QMarginsF margins = getMargins(); - const QRectF bounds = QRectF(0, 0, window->width(), window->height()).marginsRemoved(margins); + const QRectF bounds(qMax(0.0, margins.left()), + qMax(0.0, margins.top()), + window->width() - qMax(0.0, margins.left()) - qMax(0.0, margins.right()), + window->height() - qMax(0.0, margins.top()) - qMax(0.0, margins.bottom())); // if the popup doesn't fit horizontally inside the window, try flipping it around (left <-> right) if (allowHorizontalFlip && (rect.left() < bounds.left() || rect.right() > bounds.right())) { diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index 919bfffc..ae1c7185 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -355,6 +355,30 @@ TestCase { control.destroy() } + function test_negativeMargins() { + var control = popupControl.createObject(testCase, {implicitWidth: testCase.width, implicitHeight: testCase.height}) + verify(control) + + control.open() + verify(control.visible) + + compare(control.x, 0) + compare(control.y, 0) + + compare(control.margins, -1) + compare(control.topMargin, -1) + compare(control.leftMargin, -1) + compare(control.rightMargin, -1) + compare(control.bottomMargin, -1) + + control.x = -10 + control.y = -10 + compare(control.x, 0) + compare(control.y, 0) + + control.destroy() + } + function test_margins() { var control = popupControl.createObject(testCase, {width: 100, height: 100}) verify(control) -- cgit v1.2.3 From 3ed4944a7e21191ee726ca31c4e50bd055f9d25b Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 20 Sep 2016 17:23:16 +0200 Subject: Fix QQuickPopup::resetWidth/Height() When reseting the explicit size of a popup, the popup items geometry does not necessarily change. However, it affects the positioning of the popup whether it has explicit size or not. For that reason we must ensure that the popup gets repositioned as appropriate. Change-Id: I2dcd895eb7a1adc9c6a804bed4731edac1d550ec Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickpopup.cpp | 10 ++++++++++ tests/auto/controls/data/tst_popup.qml | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 2a48473a..22b399b1 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -929,8 +929,13 @@ void QQuickPopup::setWidth(qreal width) void QQuickPopup::resetWidth() { Q_D(QQuickPopup); + if (!d->hasWidth) + return; + d->hasWidth = false; d->popupItem->resetWidth(); + if (d->popupItem->isVisible()) + d->reposition(); } /*! @@ -954,8 +959,13 @@ void QQuickPopup::setHeight(qreal height) void QQuickPopup::resetHeight() { Q_D(QQuickPopup); + if (!d->hasHeight) + return; + d->hasHeight = false; d->popupItem->resetHeight(); + if (d->popupItem->isVisible()) + d->reposition(); } /*! diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index ae1c7185..8d8f94b7 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -355,6 +355,24 @@ TestCase { control.destroy() } + function test_resetSize() { + var control = popupControl.createObject(testCase, {visible: true, margins: 0}) + verify(control) + + control.width = control.implicitWidth = testCase.width + 10 + control.height = control.implicitHeight = testCase.height + 10 + + compare(control.width, testCase.width + 10) + compare(control.height, testCase.height + 10) + + control.width = undefined + control.height = undefined + compare(control.width, testCase.width) + compare(control.height, testCase.height) + + control.destroy() + } + function test_negativeMargins() { var control = popupControl.createObject(testCase, {implicitWidth: testCase.width, implicitHeight: testCase.height}) verify(control) -- cgit v1.2.3 From aae5b793666091a780e63b68b2a0426f8edd6174 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 21 Sep 2016 13:55:25 +0200 Subject: Make ApplicationWindow.overlay attached property work with QML Window Since 14dd934c, we're using QQuickOverlay even with plain QML Window. Now that the overlay is guaranteed to always exist, we can make the attached property to give a reliable access to the overlay. Change-Id: I707fc52f6dfc7a0dbc9a3467646fb5feb36b9572 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickapplicationwindow.cpp | 88 ++++++++++++---------- .../applicationwindow/tst_applicationwindow.cpp | 4 +- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index 2afdf15c..67fcd78b 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -615,47 +615,49 @@ public: void windowChange(QQuickWindow *wnd); - QQuickApplicationWindow *window; + QQuickWindow *window; }; void QQuickApplicationWindowAttachedPrivate::windowChange(QQuickWindow *wnd) { Q_Q(QQuickApplicationWindowAttached); - if (window && !QQuickApplicationWindowPrivate::get(window)) - window = nullptr; // being deleted (QTBUG-52731) + if (window == wnd) + return; - QQuickApplicationWindow *newWindow = qobject_cast(wnd); - if (window != newWindow) { - QQuickApplicationWindow *oldWindow = window; - if (oldWindow) { - QObject::disconnect(oldWindow, &QQuickApplicationWindow::activeFocusControlChanged, - q, &QQuickApplicationWindowAttached::activeFocusControlChanged); - QObject::disconnect(oldWindow, &QQuickApplicationWindow::headerChanged, - q, &QQuickApplicationWindowAttached::headerChanged); - QObject::disconnect(oldWindow, &QQuickApplicationWindow::footerChanged, - q, &QQuickApplicationWindowAttached::footerChanged); - } - if (newWindow) { - QObject::connect(newWindow, &QQuickApplicationWindow::activeFocusControlChanged, - q, &QQuickApplicationWindowAttached::activeFocusControlChanged); - QObject::connect(newWindow, &QQuickApplicationWindow::headerChanged, - q, &QQuickApplicationWindowAttached::headerChanged); - QObject::connect(newWindow, &QQuickApplicationWindow::footerChanged, - q, &QQuickApplicationWindowAttached::footerChanged); - } + QQuickApplicationWindow *oldWindow = qobject_cast(window); + if (oldWindow && !QQuickApplicationWindowPrivate::get(oldWindow)) + oldWindow = nullptr; // being deleted (QTBUG-52731) + + if (oldWindow) { + QObject::disconnect(oldWindow, &QQuickApplicationWindow::activeFocusControlChanged, + q, &QQuickApplicationWindowAttached::activeFocusControlChanged); + QObject::disconnect(oldWindow, &QQuickApplicationWindow::headerChanged, + q, &QQuickApplicationWindowAttached::headerChanged); + QObject::disconnect(oldWindow, &QQuickApplicationWindow::footerChanged, + q, &QQuickApplicationWindowAttached::footerChanged); + } - window = newWindow; - emit q->windowChanged(); - emit q->contentItemChanged(); - emit q->overlayChanged(); - - if ((oldWindow && oldWindow->activeFocusControl()) || (newWindow && newWindow->activeFocusControl())) - emit q->activeFocusControlChanged(); - if ((oldWindow && oldWindow->header()) || (newWindow && newWindow->header())) - emit q->headerChanged(); - if ((oldWindow && oldWindow->footer()) || (newWindow && newWindow->footer())) - emit q->footerChanged(); + QQuickApplicationWindow *newWindow = qobject_cast(wnd); + if (newWindow) { + QObject::connect(newWindow, &QQuickApplicationWindow::activeFocusControlChanged, + q, &QQuickApplicationWindowAttached::activeFocusControlChanged); + QObject::connect(newWindow, &QQuickApplicationWindow::headerChanged, + q, &QQuickApplicationWindowAttached::headerChanged); + QObject::connect(newWindow, &QQuickApplicationWindow::footerChanged, + q, &QQuickApplicationWindowAttached::footerChanged); } + + window = wnd; + emit q->windowChanged(); + emit q->contentItemChanged(); + emit q->overlayChanged(); + + if ((oldWindow && oldWindow->activeFocusControl()) || (newWindow && newWindow->activeFocusControl())) + emit q->activeFocusControlChanged(); + if ((oldWindow && oldWindow->header()) || (newWindow && newWindow->header())) + emit q->headerChanged(); + if ((oldWindow && oldWindow->footer()) || (newWindow && newWindow->footer())) + emit q->footerChanged(); } QQuickApplicationWindowAttached::QQuickApplicationWindowAttached(QObject *parent) @@ -691,7 +693,7 @@ QQuickApplicationWindowAttached::QQuickApplicationWindowAttached(QObject *parent QQuickApplicationWindow *QQuickApplicationWindowAttached::window() const { Q_D(const QQuickApplicationWindowAttached); - return d->window; + return qobject_cast(d->window); } /*! @@ -704,7 +706,9 @@ QQuickApplicationWindow *QQuickApplicationWindowAttached::window() const QQuickItem *QQuickApplicationWindowAttached::contentItem() const { Q_D(const QQuickApplicationWindowAttached); - return d->window ? d->window->contentItem() : nullptr; + if (QQuickApplicationWindow *window = qobject_cast(d->window)) + return window->contentItem(); + return nullptr; } /*! @@ -721,7 +725,9 @@ QQuickItem *QQuickApplicationWindowAttached::contentItem() const QQuickItem *QQuickApplicationWindowAttached::activeFocusControl() const { Q_D(const QQuickApplicationWindowAttached); - return d->window ? d->window->activeFocusControl() : nullptr; + if (QQuickApplicationWindow *window = qobject_cast(d->window)) + return window->activeFocusControl(); + return nullptr; } /*! @@ -735,7 +741,9 @@ QQuickItem *QQuickApplicationWindowAttached::activeFocusControl() const QQuickItem *QQuickApplicationWindowAttached::header() const { Q_D(const QQuickApplicationWindowAttached); - return d->window ? d->window->header() : nullptr; + if (QQuickApplicationWindow *window = qobject_cast(d->window)) + return window->header(); + return nullptr; } /*! @@ -749,7 +757,9 @@ QQuickItem *QQuickApplicationWindowAttached::header() const QQuickItem *QQuickApplicationWindowAttached::footer() const { Q_D(const QQuickApplicationWindowAttached); - return d->window ? d->window->footer() : nullptr; + if (QQuickApplicationWindow *window = qobject_cast(d->window)) + return window->footer(); + return nullptr; } /*! @@ -762,7 +772,7 @@ QQuickItem *QQuickApplicationWindowAttached::footer() const QQuickOverlay *QQuickApplicationWindowAttached::overlay() const { Q_D(const QQuickApplicationWindowAttached); - return d->window ? d->window->overlay() : nullptr; + return QQuickOverlay::overlay(d->window); } QT_END_NAMESPACE diff --git a/tests/auto/applicationwindow/tst_applicationwindow.cpp b/tests/auto/applicationwindow/tst_applicationwindow.cpp index 02528fdc..2f91f664 100644 --- a/tests/auto/applicationwindow/tst_applicationwindow.cpp +++ b/tests/auto/applicationwindow/tst_applicationwindow.cpp @@ -318,7 +318,7 @@ void tst_applicationwindow::attachedProperties() QVERIFY(!childWindowControl->property("attached_activeFocusControl").value()); QVERIFY(!childWindowControl->property("attached_header").value()); QVERIFY(!childWindowControl->property("attached_footer").value()); - QVERIFY(!childWindowControl->property("attached_overlay").value()); + QCOMPARE(childWindowControl->property("attached_overlay").value(), QQuickOverlay::overlay(childWindow)); QQuickItem *childWindowItem = object->property("childWindowItem").value(); QVERIFY(childWindowItem); @@ -327,7 +327,7 @@ void tst_applicationwindow::attachedProperties() QVERIFY(!childWindowItem->property("attached_activeFocusControl").value()); QVERIFY(!childWindowItem->property("attached_header").value()); QVERIFY(!childWindowItem->property("attached_footer").value()); - QVERIFY(!childWindowItem->property("attached_overlay").value()); + QCOMPARE(childWindowItem->property("attached_overlay").value(), QQuickOverlay::overlay(childWindow)); QObject *childWindowObject = object->property("childWindowObject").value(); QVERIFY(childWindowObject); -- cgit v1.2.3 From 175d0ea3f80af0ca32baec489d8ea66dd4ee3418 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 21 Sep 2016 11:56:08 +0200 Subject: Drawer: reparent to the overlay by default Drawer is a special type of popup that always resides at one of the window edges. Therefore it makes sense for drawers to operate on window coordinates. Re-parenting drawers to the window overlay achieves that. Now that the window overlay is guaranteed to always exist and the ApplicationWindow.overlay attached property works even with plain QML Window, we can reliably use it as a parent for Drawer. Task-number: QTBUG-53168 Change-Id: I37c727001350217ea1d2d9c52d73b4cae44d7c8d Reviewed-by: Mitch Curtis --- src/imports/controls/Drawer.qml | 2 ++ src/imports/controls/material/Drawer.qml | 2 ++ src/imports/controls/universal/Drawer.qml | 2 ++ src/quicktemplates2/qquickdrawer.cpp | 22 ++++++++++++ tests/auto/controls/data/tst_drawer.qml | 1 + tests/auto/drawer/data/header.qml | 57 +++++++++++++++++++++++++++++++ tests/auto/drawer/tst_drawer.cpp | 32 +++++++++++++++++ 7 files changed, 118 insertions(+) create mode 100644 tests/auto/drawer/data/header.qml diff --git a/src/imports/controls/Drawer.qml b/src/imports/controls/Drawer.qml index 8cf4e5e5..9791bf0c 100644 --- a/src/imports/controls/Drawer.qml +++ b/src/imports/controls/Drawer.qml @@ -40,6 +40,8 @@ import QtQuick.Templates 2.0 as T T.Drawer { id: control + parent: T.ApplicationWindow.overlay + implicitWidth: Math.max(background ? background.implicitWidth : 0, contentWidth + leftPadding + rightPadding) implicitHeight: Math.max(background ? background.implicitHeight : 0, contentHeight + topPadding + bottomPadding) diff --git a/src/imports/controls/material/Drawer.qml b/src/imports/controls/material/Drawer.qml index b3ee94f7..1c15e689 100644 --- a/src/imports/controls/material/Drawer.qml +++ b/src/imports/controls/material/Drawer.qml @@ -42,6 +42,8 @@ import QtQuick.Controls.Material.impl 2.0 T.Drawer { id: control + parent: T.ApplicationWindow.overlay + implicitWidth: Math.max(background ? background.implicitWidth : 0, contentWidth + leftPadding + rightPadding) implicitHeight: Math.max(background ? background.implicitHeight : 0, contentHeight + topPadding + bottomPadding) diff --git a/src/imports/controls/universal/Drawer.qml b/src/imports/controls/universal/Drawer.qml index 95fef8d1..84831323 100644 --- a/src/imports/controls/universal/Drawer.qml +++ b/src/imports/controls/universal/Drawer.qml @@ -41,6 +41,8 @@ import QtQuick.Controls.Universal 2.0 T.Drawer { id: control + parent: T.ApplicationWindow.overlay + implicitWidth: Math.max(background ? background.implicitWidth : 0, contentWidth + leftPadding + rightPadding) implicitHeight: Math.max(background ? background.implicitHeight : 0, contentHeight + topPadding + bottomPadding) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index 0f5e5824..4c850473 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -69,6 +69,28 @@ QT_BEGIN_NAMESPACE of the window. \endtable + \code + import QtQuick 2.7 + import QtQuick.Controls 2.0 + + ApplicationWindow { + id: window + visible: true + + Drawer { + id: drawer + width: 0.66 * window.width + height: window.height + } + } + \endcode + + Drawer is a special type of popup that resides at one of the window \l {edge}{edges}. + By default, Drawer re-parents itself to the window \l {ApplicationWindow::}{overlay}, + and therefore operates on window coordinates. It is also possible to manually set the + \l {Popup::}{parent} to something else to make the drawer operate in a specific + coordinate space. + In the image above, the application's contents are \e "pushed" across the screen. This is achieved by applying a translation to the contents: diff --git a/tests/auto/controls/data/tst_drawer.qml b/tests/auto/controls/data/tst_drawer.qml index e08856bd..021afdb2 100644 --- a/tests/auto/controls/data/tst_drawer.qml +++ b/tests/auto/controls/data/tst_drawer.qml @@ -60,6 +60,7 @@ TestCase { compare(control.edge, Qt.LeftEdge) compare(control.position, 0.0) compare(control.dragMargin, Qt.styleHints.startDragDistance) + compare(control.parent, ApplicationWindow.overlay) control.destroy() } diff --git a/tests/auto/drawer/data/header.qml b/tests/auto/drawer/data/header.qml new file mode 100644 index 00000000..9a352ffc --- /dev/null +++ b/tests/auto/drawer/data/header.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + + header: ToolBar { } + + Drawer { + id: drawer + width: 200 + height: parent.height + } +} diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index 3a02e9a9..f29abf21 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -69,6 +69,7 @@ private slots: void dragMargin(); void reposition(); + void header(); void hover_data(); void hover(); @@ -352,6 +353,37 @@ void tst_Drawer::reposition() QTRY_COMPARE(drawer->popupItem()->x(), static_cast(window->width())); } +void tst_Drawer::header() +{ + QQuickApplicationHelper helper(this, QStringLiteral("header.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickItem *content = window->contentItem(); + QVERIFY(content); + + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + + QQuickDrawer *drawer = window->property("drawer").value(); + QVERIFY(drawer); + QQuickItem *popupItem = drawer->popupItem(); + + drawer->open(); + QVERIFY(drawer->isVisible()); + + QCOMPARE(drawer->parentItem(), overlay); + QCOMPARE(drawer->height(), overlay->height()); + QCOMPARE(popupItem->height(), overlay->height()); + + drawer->setParentItem(content); + QCOMPARE(drawer->parentItem(), content); + QCOMPARE(drawer->height(), content->height()); + QCOMPARE(popupItem->height(), content->height()); +} + void tst_Drawer::hover_data() { QTest::addColumn("source"); -- cgit v1.2.3 From 244356ba182c2807ef9b15eb71ac16a568d65642 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 15 Sep 2016 10:09:36 +0200 Subject: QQuickDrawer: allow resizing and positioning Make QQuickDrawer re-use QQuickPopup's reposition() implementation. This way QQuickDrawer gains support for proper positioning and margins "for free". Now it is possible to place Drawer below the window header, for instance: import QtQuick 2.0 import QtQuick.Controls 2.0 ApplicationWindow { id: window visible: true header: ToolBar { } Drawer { y: header.height width: window.width * 0.6 height: window.height - header.height } } [ChangeLog][Controls][Drawer] Made it possible to control the vertical position of a horizontal drawer, and vice versa. This allows placing a drawer below a header/toolbar, for instance. Task-number: QTBUG-55360 Change-Id: I63621195efeefa2ea88935d676771b392e0a4030 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 73 +++++++++++++++++++++++++++++- src/quicktemplates2/qquickdrawer_p.h | 2 + src/quicktemplates2/qquickdrawer_p_p.h | 3 ++ src/quicktemplates2/qquickpopup.cpp | 81 +++++++++++++++++++++------------- src/quicktemplates2/qquickpopup_p_p.h | 4 ++ tests/auto/drawer/data/reposition.qml | 58 ++++++++++++++++++++++++ tests/auto/drawer/tst_drawer.cpp | 47 ++++++++++++++++---- 7 files changed, 228 insertions(+), 40 deletions(-) create mode 100644 tests/auto/drawer/data/reposition.qml diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index 4c850473..80cd95c9 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -91,6 +91,32 @@ QT_BEGIN_NAMESPACE \l {Popup::}{parent} to something else to make the drawer operate in a specific coordinate space. + Drawer can be configured to cover only part of its window edge. The following example + illustrates how Drawer can be positioned to appear below a window header: + + \code + import QtQuick 2.7 + import QtQuick.Controls 2.0 + + ApplicationWindow { + id: window + visible: true + + header: ToolBar { } + + Drawer { + y: header.height + width: window.width * 0.6 + height: window.height - header.height + } + } + \endcode + + The \l position property determines how much of the drawer is visible, as + a value between \c 0.0 and \c 1.0. It is not possible to set the x-coordinate + (or horizontal margins) of a drawer at the left or right window edge, or the + y-coordinate (or vertical margins) of a drawer at the top or bottom window edge. + In the image above, the application's contents are \e "pushed" across the screen. This is achieved by applying a translation to the contents: @@ -139,6 +165,7 @@ QQuickDrawerPrivate::QQuickDrawerPrivate() : edge(Qt::LeftEdge), offset(0), position(0), dragMargin(QGuiApplication::styleHints()->startDragDistance()) { + setEdge(Qt::LeftEdge); } qreal QQuickDrawerPrivate::positionAt(const QPointF &point) const @@ -183,6 +210,27 @@ void QQuickDrawerPrivate::reposition() popupItem->setY(window->height() - position * popupItem->height()); break; } + + QQuickPopupPrivate::reposition(); +} + +void QQuickDrawerPrivate::resizeOverlay() +{ + if (!dimmer || !window) + return; + + QRectF geometry(0, 0, window->width(), window->height()); + + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) { + geometry.setY(popupItem->y()); + geometry.setHeight(popupItem->height()); + } else { + geometry.setX(popupItem->x()); + geometry.setWidth(popupItem->width()); + } + + dimmer->setPosition(geometry.topLeft()); + dimmer->setSize(geometry.size()); } static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int threshold = -1) @@ -402,6 +450,22 @@ bool QQuickDrawerPrivate::prepareExitTransition() return QQuickPopupPrivate::prepareExitTransition(); } +void QQuickDrawerPrivate::setEdge(Qt::Edge e) +{ + edge = e; + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) { + allowVerticalMove = true; + allowVerticalResize = true; + allowHorizontalMove = false; + allowHorizontalResize = false; + } else { + allowVerticalMove = false; + allowVerticalResize = false; + allowHorizontalMove = true; + allowHorizontalResize = true; + } +} + QQuickDrawer::QQuickDrawer(QObject *parent) : QQuickPopup(*(new QQuickDrawerPrivate), parent) { @@ -434,7 +498,7 @@ void QQuickDrawer::setEdge(Qt::Edge edge) if (d->edge == edge) return; - d->edge = edge; + d->setEdge(edge); if (isComponentComplete()) d->reposition(); emit edgeChanged(); @@ -559,4 +623,11 @@ bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event) } } +void QQuickDrawer::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickDrawer); + QQuickPopup::geometryChanged(newGeometry, oldGeometry); + d->resizeOverlay(); +} + QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickdrawer_p.h b/src/quicktemplates2/qquickdrawer_p.h index e694e27b..bada1344 100644 --- a/src/quicktemplates2/qquickdrawer_p.h +++ b/src/quicktemplates2/qquickdrawer_p.h @@ -87,6 +87,8 @@ protected: void mouseUngrabEvent() override; bool overlayEvent(QQuickItem *item, QEvent *event) override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + private: Q_DISABLE_COPY(QQuickDrawer) Q_DECLARE_PRIVATE(QQuickDrawer) diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h index f14c36dd..b7555c3e 100644 --- a/src/quicktemplates2/qquickdrawer_p_p.h +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -68,6 +68,7 @@ public: qreal positionAt(const QPointF &point) const; void reposition() override; + void resizeOverlay() override; bool startDrag(QQuickWindow *window, QMouseEvent *event); bool grabMouse(QMouseEvent *event); @@ -80,6 +81,8 @@ public: bool prepareEnterTransition() override; bool prepareExitTransition() override; + void setEdge(Qt::Edge edge); + Qt::Edge edge; qreal offset; qreal position; diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 22b399b1..6deda711 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -133,6 +133,10 @@ QQuickPopupPrivate::QQuickPopupPrivate() , hasBottomMargin(false) , allowVerticalFlip(false) , allowHorizontalFlip(false) + , allowVerticalMove(true) + , allowHorizontalMove(true) + , allowVerticalResize(true) + , allowHorizontalResize(true) , hadActiveFocusBeforeExitTransition(false) , x(0) , y(0) @@ -589,7 +593,10 @@ void QQuickPopupPrivate::reposition() bool widthAdjusted = false; bool heightAdjusted = false; - QRectF rect(x, y, !hasWidth && iw > 0 ? iw : w, !hasHeight && ih > 0 ? ih : h); + QRectF rect(allowHorizontalMove ? x : popupItem->x(), + allowVerticalMove ? y : popupItem->y(), + !hasWidth && iw > 0 ? iw : w, + !hasHeight && ih > 0 ? ih : h); if (parentItem) { rect = parentItem->mapRectToScene(rect); @@ -615,31 +622,39 @@ void QQuickPopupPrivate::reposition() } // push inside the margins if specified - if (margins.top() >= 0 && rect.top() < bounds.top()) - rect.moveTop(margins.top()); - if (margins.bottom() >= 0 && rect.bottom() > bounds.bottom()) - rect.moveBottom(bounds.bottom()); - if (margins.left() >= 0 && rect.left() < bounds.left()) - rect.moveLeft(margins.left()); - if (margins.right() >= 0 && rect.right() > bounds.right()) - rect.moveRight(bounds.right()); + if (allowVerticalMove) { + if (margins.top() >= 0 && rect.top() < bounds.top()) + rect.moveTop(margins.top()); + if (margins.bottom() >= 0 && rect.bottom() > bounds.bottom()) + rect.moveBottom(bounds.bottom()); + } + if (allowHorizontalMove) { + if (margins.left() >= 0 && rect.left() < bounds.left()) + rect.moveLeft(margins.left()); + if (margins.right() >= 0 && rect.right() > bounds.right()) + rect.moveRight(bounds.right()); + } if (iw > 0 && (rect.left() < bounds.left() || rect.right() > bounds.right())) { // neither the flipped or pushed geometry fits inside the window, choose // whichever side (left vs. right) fits larger part of the popup - if (rect.left() < bounds.left() && bounds.left() + rect.width() <= bounds.right()) - rect.moveLeft(bounds.left()); - else if (rect.right() > bounds.right() && bounds.right() - rect.width() >= bounds.left()) - rect.moveRight(bounds.right()); + if (allowHorizontalMove && allowHorizontalFlip) { + if (rect.left() < bounds.left() && bounds.left() + rect.width() <= bounds.right()) + rect.moveLeft(bounds.left()); + else if (rect.right() > bounds.right() && bounds.right() - rect.width() >= bounds.left()) + rect.moveRight(bounds.right()); + } // as a last resort, adjust the width to fit the window - if (rect.left() < bounds.left()) { - rect.setLeft(bounds.left()); - widthAdjusted = true; - } - if (rect.right() > bounds.right()) { - rect.setRight(bounds.right()); - widthAdjusted = true; + if (allowHorizontalResize) { + if (rect.left() < bounds.left()) { + rect.setLeft(bounds.left()); + widthAdjusted = true; + } + if (rect.right() > bounds.right()) { + rect.setRight(bounds.right()); + widthAdjusted = true; + } } } else if (iw > 0 && rect.left() >= bounds.left() && rect.right() <= bounds.right() && iw != w) { @@ -651,19 +666,23 @@ void QQuickPopupPrivate::reposition() if (ih > 0 && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) { // neither the flipped or pushed geometry fits inside the window, choose // whichever side (above vs. below) fits larger part of the popup - if (rect.top() < bounds.top() && bounds.top() + rect.height() <= bounds.bottom()) - rect.moveTop(bounds.top()); - else if (rect.bottom() > bounds.bottom() && bounds.bottom() - rect.height() >= bounds.top()) - rect.moveBottom(bounds.bottom()); + if (allowVerticalMove && allowVerticalFlip) { + if (rect.top() < bounds.top() && bounds.top() + rect.height() <= bounds.bottom()) + rect.moveTop(bounds.top()); + else if (rect.bottom() > bounds.bottom() && bounds.bottom() - rect.height() >= bounds.top()) + rect.moveBottom(bounds.bottom()); + } // as a last resort, adjust the height to fit the window - if (rect.top() < bounds.top()) { - rect.setTop(bounds.top()); - heightAdjusted = true; - } - if (rect.bottom() > bounds.bottom()) { - rect.setBottom(bounds.bottom()); - heightAdjusted = true; + if (allowVerticalResize) { + if (rect.top() < bounds.top()) { + rect.setTop(bounds.top()); + heightAdjusted = true; + } + if (rect.bottom() > bounds.bottom()) { + rect.setBottom(bounds.bottom()); + heightAdjusted = true; + } } } else if (ih > 0 && rect.top() >= bounds.top() && rect.bottom() <= bounds.bottom() && ih != h) { diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h index 321adaf5..c9f5e264 100644 --- a/src/quicktemplates2/qquickpopup_p_p.h +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -192,6 +192,10 @@ public: bool hasBottomMargin; bool allowVerticalFlip; bool allowHorizontalFlip; + bool allowVerticalMove; + bool allowHorizontalMove; + bool allowVerticalResize; + bool allowHorizontalResize; bool hadActiveFocusBeforeExitTransition; qreal x; qreal y; diff --git a/tests/auto/drawer/data/reposition.qml b/tests/auto/drawer/data/reposition.qml new file mode 100644 index 00000000..abaec5ae --- /dev/null +++ b/tests/auto/drawer/data/reposition.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + + header: Item { implicitHeight: 50 } + footer: Item { implicitHeight: 50 } + + Drawer { + id: drawer + width: parent.width / 2 + implicitHeight: parent.height + } +} diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index f29abf21..19a66326 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -330,27 +331,57 @@ void tst_Drawer::dragMargin() QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - rightDistance, drawer->height() / 2)); } +static QRectF geometry(const QQuickItem *item) +{ + return QRectF(item->x(), item->y(), item->width(), item->height()); +} + void tst_Drawer::reposition() { - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QQuickApplicationHelper helper(this, QStringLiteral("reposition.qml")); QQuickApplicationWindow *window = helper.appWindow; window->show(); - window->requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QTest::qWaitForWindowExposed(window)); - QQuickDrawer *drawer = helper.appWindow->property("drawer").value(); + QQuickDrawer *drawer = window->property("drawer").value(); QVERIFY(drawer); - drawer->setEdge(Qt::RightEdge); + QQuickItem *popupItem = drawer->popupItem(); + QVERIFY(popupItem); drawer->open(); - QTRY_COMPARE(drawer->popupItem()->x(), window->width() - drawer->width()); + QQuickItem *dimmer = QQuickPopupPrivate::get(drawer)->dimmer; + QVERIFY(dimmer); + + QCOMPARE(geometry(dimmer), QRectF(0, 0, window->width(), window->height())); + QTRY_COMPARE(geometry(popupItem), QRectF(0, 0, window->width() / 2, window->height())); + + drawer->setY(100); + QCOMPARE(geometry(dimmer), QRectF(0, 100, window->width(), window->height() - 100)); + QCOMPARE(geometry(popupItem), QRectF(0, 100, window->width() / 2, window->height() - 100)); + + drawer->setHeight(window->height()); + QCOMPARE(geometry(dimmer), QRectF(0, 100, window->width(), window->height())); + QCOMPARE(geometry(popupItem), QRectF(0, 100, window->width() / 2, window->height())); + + drawer->resetHeight(); + QCOMPARE(geometry(dimmer), QRectF(0, 100, window->width(), window->height() - 100)); + QCOMPARE(geometry(popupItem), QRectF(0, 100, window->width() / 2, window->height() - 100)); + + drawer->setParentItem(window->contentItem()); + QCOMPARE(geometry(dimmer), QRectF(0, 150, window->width(), window->height() - 150)); + QCOMPARE(geometry(popupItem), QRectF(0, 150, window->width() / 2, window->height() - 150)); + + drawer->setEdge(Qt::RightEdge); + QCOMPARE(geometry(dimmer), QRectF(0, 150, window->width(), window->height() - 150)); + QTRY_COMPARE(geometry(popupItem), QRectF(window->width() - drawer->width(), 150, window->width() / 2, window->height() - 150)); window->setWidth(window->width() + 100); - QTRY_COMPARE(drawer->popupItem()->x(), window->width() - drawer->width()); + QTRY_COMPARE(geometry(dimmer), QRectF(0, 150, window->width(), window->height() - 150)); + QCOMPARE(geometry(popupItem), QRectF(window->width() - drawer->width(), 150, window->width() / 2, window->height() - 150)); drawer->close(); - QTRY_COMPARE(drawer->popupItem()->x(), static_cast(window->width())); + QTRY_COMPARE(geometry(popupItem), QRectF(window->width(), 150, window->width() / 2, window->height() - 150)); } void tst_Drawer::header() -- cgit v1.2.3 From 292266d5f728f0a8ad5f288954ac7ebe4210a2a3 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 21 Sep 2016 13:30:01 +0200 Subject: Menu: fix documentation review findings Change-Id: I1ae17f1e6241b46b6d2f321451fd4fd017032486 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickmenu.cpp | 42 ++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index bc594c03..f5a4bac6 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -89,6 +89,15 @@ QT_BEGIN_NAMESPACE } \endcode + Typically, menu items are statically declared as children of the menu, but + Menu also provides API to \l {addItem}{add}, \l {insertItem}{insert}, + \l {moveItem}{move} and \l {removeItem}{remove} items dynamically. The + items in a menu can be accessed using \l itemAt() or + \l {Popup::}{contentChildren}. + + Although \l {MenuItem}{MenuItems} are most commonly used with Menu, it can + contain any type of item. + \sa {Customizing Menu}, {Menu Controls}, {Popup Controls} */ @@ -350,7 +359,7 @@ void QQuickMenu::moveItem(int from, int to) /*! \qmlmethod void QtQuick.Controls::Menu::removeItem(int index) - Removes an item at \a index. + Removes the item at \a index. \note The ownership of the item is transferred to the caller. */ @@ -372,8 +381,20 @@ void QQuickMenu::removeItem(int index) This property holds the model used to display menu items. - By default, the model is an \l ObjectModel, in order to allow declaring - menu items as children of the menu. + The content model is provided for visualization purposes. It can be assigned + as a model to a content item that presents the contents of the menu. + + \code + Menu { + id: menu + contentItem: ListView { + model: menu.contentModel + } + } + \endcode + + The model allows menu items to be statically declared as children of the + menu. */ QVariant QQuickMenu::contentModel() const { @@ -387,7 +408,14 @@ QVariant QQuickMenu::contentModel() const This property holds the list of content data. - \sa Item::data + The list contains all objects that have been declared in QML as children + of the menu, and also items that have been dynamically added or + inserted using the \l addItem() and \l insertItem() methods, respectively. + + \note Unlike \c contentChildren, \c contentData does include non-visual QML + objects. It is not re-ordered when items are inserted or moved. + + \sa Item::data, contentChildren */ QQmlListProperty QQuickMenu::contentData() { @@ -402,9 +430,11 @@ QQmlListProperty QQuickMenu::contentData() /*! \qmlproperty string QtQuick.Controls::Menu::title - Title for the menu as a submenu or in a menubar. + This property holds the title for the menu. - Its value defaults to an empty string. + The title of a menu is often displayed in the text of a menu item when the + menu is a submenu, and in the text of a tool button when it is in a + menubar. */ QString QQuickMenu::title() const { -- cgit v1.2.3 From 54d276edc92d87a88136b2c31396e8ef45a71290 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 21 Sep 2016 13:43:24 +0200 Subject: MenuItem: fix documentation review findings Change-Id: Iff356498b438e0f4373efce0131634439b5e6240 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickmenuitem.cpp | 35 +++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/quicktemplates2/qquickmenuitem.cpp b/src/quicktemplates2/qquickmenuitem.cpp index 35942f92..902889b0 100644 --- a/src/quicktemplates2/qquickmenuitem.cpp +++ b/src/quicktemplates2/qquickmenuitem.cpp @@ -52,26 +52,30 @@ QT_BEGIN_NAMESPACE \brief A menu item within a Menu. MenuItem is a convenience type that implements the AbstractButton API, - providing an easy way to respond to menu items being clicked, for example. + providing a familiar way to respond to menu items being \l triggered, for + example. \code Button { id: fileButton text: "File" onClicked: menu.open() - } - Menu { - id: menu - anchor.target: fileButton - MenuItem { - text: "New..." - } - MenuItem { - text: "Open..." - } - MenuItem { - text: "Save" + Menu { + id: menu + + MenuItem { + text: "New..." + onTriggered: document.reset() + } + MenuItem { + text: "Open..." + onTriggered: openDialog.open() + } + MenuItem { + text: "Save" + onTriggered: saveDialog.open() + } } } \endcode @@ -110,6 +114,11 @@ QQuickMenuItem::QQuickMenuItem(QQuickItem *parent) : \qmlproperty bool QtQuick.Controls::MenuItem::checkable This property holds whether the menu item is checkable. + + A checkable menu item toggles between checked (on) and unchecked (off) when + the user clicks on it or interacts with it via the keyboard. + + \sa {AbstractButton::}{checked} */ void QQuickMenuItem::checkableChange() -- cgit v1.2.3 From 9dea203013c0a5d20fdffbb2b9a1c1dcc70435b1 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 21 Sep 2016 14:09:13 +0200 Subject: Page: fix documentation review findings Change-Id: Ia63c5d34ccb239fb45c7445a4354e6594bfce812 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickpage.cpp | 47 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickpage.cpp b/src/quicktemplates2/qquickpage.cpp index 5c2c5b42..9ee0970b 100644 --- a/src/quicktemplates2/qquickpage.cpp +++ b/src/quicktemplates2/qquickpage.cpp @@ -166,6 +166,37 @@ QQuickPage::QQuickPage(QQuickItem *parent) : \qmlproperty string QtQuick.Controls::Page::title This property holds the page title. + + The title is often displayed at the top of a page to give + the user context about the page they are viewing. + + \code + ApplicationWindow { + visible: true + width: 400 + height: 400 + + header: Label { + text: view.currentItem.title + horizontalAlignment: Text.AlignHCenter + } + + SwipeView { + id: view + anchors.fill: parent + + Page { + title: qsTr("Home") + } + Page { + title: qsTr("Discover") + } + Page { + title: qsTr("Activity") + } + } + } + \endcode */ QString QQuickPage::title() const @@ -281,7 +312,13 @@ void QQuickPage::setFooter(QQuickItem *footer) This property holds the list of content data. - \sa Item::data + The list contains all objects that have been declared in QML as children + of the container. + + \note Unlike \c contentChildren, \c contentData does include non-visual QML + objects. + + \sa Item::data, contentChildren */ QQmlListProperty QQuickPage::contentData() { @@ -298,7 +335,13 @@ QQmlListProperty QQuickPage::contentData() This property holds the list of content children. - \sa Item::children + The list contains all items that have been declared in QML as children + of the page. + + \note Unlike \c contentData, \c contentChildren does not include non-visual + QML objects. + + \sa Item::children, contentData */ QQmlListProperty QQuickPage::contentChildren() { -- cgit v1.2.3 From 7193318330bc518255fb7ed008c144578f49b4bd Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 20 Sep 2016 15:49:21 +0200 Subject: Control: add example snippets for background, contentItem and font Change-Id: I0968454452dcf17093ef27af8770fd5018780160 Task-number: QTBUG-55904 Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickcontrol.cpp | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index 8c5c75d2..518255dd 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -454,6 +454,22 @@ void QQuickControl::itemChange(QQuickItem::ItemChange change, const QQuickItem:: Control propagates explicit font properties from parent to children. If you change a specific property on a control's font, that property propagates to all of the control's children, overriding any system defaults for that property. + + \code + Page { + font.family: "Courier" + + Column { + Label { + text: qsTr("This will use Courier...") + } + + Switch { + text: qsTr("... and so will this") + } + } + } + \endcode */ QFont QQuickControl::font() const { @@ -987,6 +1003,19 @@ void QQuickControl::setWheelEnabled(bool enabled) This property holds the background item. + \code + Button { + id: control + text: qsTr("Button") + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + opacity: enabled ? 1 : 0.3 + color: control.down ? "#d0d0d0" : "#e0e0e0" + } + } + \endcode + \note If the background item has no explicit size specified, it automatically follows the control's size. In most cases, there is no need to specify width or height for a background item. @@ -1037,6 +1066,18 @@ void QQuickControl::setBackground(QQuickItem *background) size for it (unless it is an item like \l Text which has its own implicit size). + \code + Button { + id: control + text: qsTr("Button") + contentItem: Label { + text: control.text + font: control.font + verticalAlignment: Text.AlignVCenter + } + } + \endcode + \sa {Control Layout}, padding */ QQuickItem *QQuickControl::contentItem() const -- cgit v1.2.3