From ed64115cbf11a758a9cacd2bd34f3af5603f73b7 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 4 Apr 2017 16:18:39 +0200 Subject: Set explicit cursors on all interactive controls For example, if you have a floating button on top of a text editor, hovering the button must change the cursor from the editor's ibeam cursor to an arrow cursor. This applies to all interactive controls that call setAcceptedMouseButtons(). If a control blocks mouse events, it should not use some random cursor from another control underneath. Task-number: QTBUG-59629 Change-Id: I8a6ae306bbc76a9b22377361cb19cf9c3a872d31 Reviewed-by: Mitch Curtis --- src/imports/calendar/qquickmonthgrid.cpp | 3 + src/quicktemplates2/qquickabstractbutton.cpp | 6 ++ src/quicktemplates2/qquickcombobox.cpp | 12 +++ src/quicktemplates2/qquickdial.cpp | 3 + src/quicktemplates2/qquickoverlay.cpp | 3 + src/quicktemplates2/qquickpage.cpp | 3 + src/quicktemplates2/qquickpageindicator.cpp | 12 ++- src/quicktemplates2/qquickpane.cpp | 6 ++ src/quicktemplates2/qquickrangeslider.cpp | 5 +- src/quicktemplates2/qquickscrollbar.cpp | 13 ++- src/quicktemplates2/qquickslider.cpp | 3 + src/quicktemplates2/qquickspinbox.cpp | 17 ++++ tests/auto/cursor/data/buttons.qml | 104 ++++++++++++++++++++++++ tests/auto/cursor/data/containers.qml | 77 ++++++++++++++++++ tests/auto/cursor/data/editable.qml | 72 +++++++++++++++++ tests/auto/cursor/data/pageindicator.qml | 62 +++++++++++++++ tests/auto/cursor/data/sliders.qml | 71 +++++++++++++++++ tests/auto/cursor/tst_cursor.cpp | 114 ++++++++++++++++++++++++++- 18 files changed, 581 insertions(+), 5 deletions(-) create mode 100644 tests/auto/cursor/data/buttons.qml create mode 100644 tests/auto/cursor/data/containers.qml create mode 100644 tests/auto/cursor/data/editable.qml create mode 100644 tests/auto/cursor/data/pageindicator.qml create mode 100644 tests/auto/cursor/data/sliders.qml diff --git a/src/imports/calendar/qquickmonthgrid.cpp b/src/imports/calendar/qquickmonthgrid.cpp index 5eb0798c..9621f49a 100644 --- a/src/imports/calendar/qquickmonthgrid.cpp +++ b/src/imports/calendar/qquickmonthgrid.cpp @@ -195,6 +195,9 @@ QQuickMonthGrid::QQuickMonthGrid(QQuickItem *parent) : setFlag(ItemIsFocusScope); setActiveFocusOnTab(true); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif d->model = new QQuickMonthModel(this); d->source = QVariant::fromValue(d->model); diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index 225ab9ab..7c2ced66 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -308,6 +308,9 @@ QQuickAbstractButton::QQuickAbstractButton(QQuickItem *parent) setActiveFocusOnTab(true); setFocusPolicy(Qt::StrongFocus); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } QQuickAbstractButton::QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQuickItem *parent) @@ -316,6 +319,9 @@ QQuickAbstractButton::QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQui setActiveFocusOnTab(true); setFocusPolicy(Qt::StrongFocus); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } QQuickAbstractButton::~QQuickAbstractButton() diff --git a/src/quicktemplates2/qquickcombobox.cpp b/src/quicktemplates2/qquickcombobox.cpp index 786db55b..85c577b4 100644 --- a/src/quicktemplates2/qquickcombobox.cpp +++ b/src/quicktemplates2/qquickcombobox.cpp @@ -628,6 +628,9 @@ QQuickComboBox::QQuickComboBox(QQuickItem *parent) setFocusPolicy(Qt::StrongFocus); setFlag(QQuickItem::ItemIsFocusScope); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif setInputMethodHints(Qt::ImhNoPredictiveText); } @@ -737,12 +740,18 @@ void QQuickComboBox::setEditable(bool editable) QObjectPrivate::connect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText); QObjectPrivate::connect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput); } +#if QT_CONFIG(cursor) + d->contentItem->setCursor(Qt::IBeamCursor); +#endif } else { d->contentItem->removeEventFilter(this); if (QQuickTextInput *input = qobject_cast(d->contentItem)) { QObjectPrivate::disconnect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText); QObjectPrivate::disconnect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput); } +#if QT_CONFIG(cursor) + d->contentItem->unsetCursor(); +#endif } } @@ -1542,6 +1551,9 @@ void QQuickComboBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) connect(newInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickComboBox::inputMethodComposingChanged); connect(newInput, &QQuickTextInput::acceptableInputChanged, this, &QQuickComboBox::acceptableInputChanged); } +#if QT_CONFIG(cursor) + newItem->setCursor(Qt::IBeamCursor); +#endif } } diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index 24a8df01..c7fbdc80 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -260,6 +260,9 @@ QQuickDial::QQuickDial(QQuickItem *parent) { setActiveFocusOnTab(true); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } /*! diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index c72979ae..d31186cd 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -97,6 +97,9 @@ static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQ item->setZ(popup->z()); if (popup->isModal()) { item->setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(cursor) + item->setCursor(Qt::ArrowCursor); +#endif #if QT_CONFIG(quicktemplates2_hover) // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 item->setAcceptHoverEvents(true); diff --git a/src/quicktemplates2/qquickpage.cpp b/src/quicktemplates2/qquickpage.cpp index 701916b6..6b0b3a38 100644 --- a/src/quicktemplates2/qquickpage.cpp +++ b/src/quicktemplates2/qquickpage.cpp @@ -117,6 +117,9 @@ QQuickPage::QQuickPage(QQuickItem *parent) Q_D(QQuickPage); setFlag(ItemIsFocusScope); setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif d->layout.reset(new QQuickPageLayout(this)); } diff --git a/src/quicktemplates2/qquickpageindicator.cpp b/src/quicktemplates2/qquickpageindicator.cpp index 92b6c0c0..b4c9c14c 100644 --- a/src/quicktemplates2/qquickpageindicator.cpp +++ b/src/quicktemplates2/qquickpageindicator.cpp @@ -247,7 +247,17 @@ void QQuickPageIndicator::setInteractive(bool interactive) return; d->interactive = interactive; - setAcceptedMouseButtons(interactive ? Qt::LeftButton : Qt::NoButton); + if (interactive) { + setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif + } else { + setAcceptedMouseButtons(Qt::NoButton); +#if QT_CONFIG(cursor) + unsetCursor(); +#endif + } emit interactiveChanged(); } diff --git a/src/quicktemplates2/qquickpane.cpp b/src/quicktemplates2/qquickpane.cpp index 6cb81316..efa85e0c 100644 --- a/src/quicktemplates2/qquickpane.cpp +++ b/src/quicktemplates2/qquickpane.cpp @@ -123,6 +123,9 @@ QQuickPane::QQuickPane(QQuickItem *parent) { setFlag(QQuickItem::ItemIsFocusScope); setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } QQuickPane::QQuickPane(QQuickPanePrivate &dd, QQuickItem *parent) @@ -130,6 +133,9 @@ QQuickPane::QQuickPane(QQuickPanePrivate &dd, QQuickItem *parent) { setFlag(QQuickItem::ItemIsFocusScope); setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } /*! diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp index 1c74f9ee..2d3c464f 100644 --- a/src/quicktemplates2/qquickrangeslider.cpp +++ b/src/quicktemplates2/qquickrangeslider.cpp @@ -521,8 +521,11 @@ QQuickRangeSlider::QQuickRangeSlider(QQuickItem *parent) d->first = new QQuickRangeSliderNode(0.0, this); d->second = new QQuickRangeSliderNode(1.0, this); - setAcceptedMouseButtons(Qt::LeftButton); setFlag(QQuickItem::ItemIsFocusScope); + setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } /*! diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp index 8f4337ae..cb5c0001 100644 --- a/src/quicktemplates2/qquickscrollbar.cpp +++ b/src/quicktemplates2/qquickscrollbar.cpp @@ -196,9 +196,18 @@ void QQuickScrollBarPrivate::setInteractive(bool enabled) return; interactive = enabled; - q->setAcceptedMouseButtons(interactive ? Qt::LeftButton : Qt::NoButton); - if (!interactive) + if (interactive) { + q->setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + q->setCursor(Qt::ArrowCursor); +#endif + } else { + q->setAcceptedMouseButtons(Qt::NoButton); +#if QT_CONFIG(cursor) + q->unsetCursor(); +#endif q->ungrabMouse(); + } emit q->interactiveChanged(); } diff --git a/src/quicktemplates2/qquickslider.cpp b/src/quicktemplates2/qquickslider.cpp index 266f883f..fbf9755d 100644 --- a/src/quicktemplates2/qquickslider.cpp +++ b/src/quicktemplates2/qquickslider.cpp @@ -243,6 +243,9 @@ QQuickSlider::QQuickSlider(QQuickItem *parent) setActiveFocusOnTab(true); setFocusPolicy(Qt::StrongFocus); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } /*! diff --git a/src/quicktemplates2/qquickspinbox.cpp b/src/quicktemplates2/qquickspinbox.cpp index 657102c3..b70366ea 100644 --- a/src/quicktemplates2/qquickspinbox.cpp +++ b/src/quicktemplates2/qquickspinbox.cpp @@ -351,6 +351,9 @@ QQuickSpinBox::QQuickSpinBox(QQuickItem *parent) setFlag(ItemIsFocusScope); setFiltersChildMouseEvents(true); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(cursor) + setCursor(Qt::ArrowCursor); +#endif } /*! @@ -470,6 +473,15 @@ void QQuickSpinBox::setEditable(bool editable) if (d->editable == editable) return; +#if QT_CONFIG(cursor) + if (d->contentItem) { + if (editable) + d->contentItem->setCursor(Qt::IBeamCursor); + else + d->contentItem->unsetCursor(); + } +#endif + d->editable = editable; emit editableChanged(); } @@ -905,11 +917,16 @@ void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value) void QQuickSpinBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) { + Q_D(QQuickSpinBox); if (QQuickTextInput *oldInput = qobject_cast(oldItem)) disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged); if (newItem) { newItem->setActiveFocusOnTab(true); +#if QT_CONFIG(cursor) + if (d->editable) + newItem->setCursor(Qt::IBeamCursor); +#endif if (QQuickTextInput *newInput = qobject_cast(newItem)) connect(newInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged); diff --git a/tests/auto/cursor/data/buttons.qml b/tests/auto/cursor/data/buttons.qml new file mode 100644 index 00000000..21226ef5 --- /dev/null +++ b/tests/auto/cursor/data/buttons.qml @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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.2 + +MouseArea { + width: column.width + height: column.height + cursorShape: Qt.ForbiddenCursor + + Column { + id: column + padding: 10 + spacing: 10 + + Button { + text: "Button" + } + CheckBox { + text: "CheckBox" + } + CheckDelegate { + text: "CheckDelegate" + } + ItemDelegate { + text: "ItemDelegate" + } + MenuItem { + text: "MenuItem" + } + RadioButton { + text: "RadioButton" + } + RadioDelegate { + text: "RadioDelegate" + } + RoundButton { + text: "X" + } + SwipeDelegate { + text: "SwipeDelegate" + } + Switch { + text: "Switch" + } + SwitchDelegate { + text: "SwitchDelegate" + } + TabButton { + text: "TabButton" + } + ToolButton { + text: "ToolButton" + } + } +} diff --git a/tests/auto/cursor/data/containers.qml b/tests/auto/cursor/data/containers.qml new file mode 100644 index 00000000..09fbbc18 --- /dev/null +++ b/tests/auto/cursor/data/containers.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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.2 + +MouseArea { + width: column.width + height: column.height + cursorShape: Qt.ForbiddenCursor + + Column { + id: column + padding: 10 + spacing: 10 + + Page { + width: 200 + height: 20 + } + Pane { + width: 200 + height: 20 + } + ToolBar { + width: 200 + height: 20 + } + } +} diff --git a/tests/auto/cursor/data/editable.qml b/tests/auto/cursor/data/editable.qml new file mode 100644 index 00000000..1956889b --- /dev/null +++ b/tests/auto/cursor/data/editable.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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.2 + +MouseArea { + width: column.width + height: column.height + cursorShape: Qt.ForbiddenCursor + + Column { + id: column + padding: 10 + spacing: 10 + + ComboBox { + editable: true + model: "ComboBox" + } + SpinBox { + editable: true + } + } +} diff --git a/tests/auto/cursor/data/pageindicator.qml b/tests/auto/cursor/data/pageindicator.qml new file mode 100644 index 00000000..1e550a78 --- /dev/null +++ b/tests/auto/cursor/data/pageindicator.qml @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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.2 + +MouseArea { + width: 200 + height: 200 + cursorShape: Qt.ForbiddenCursor + + PageIndicator { + anchors.centerIn: parent + } +} diff --git a/tests/auto/cursor/data/sliders.qml b/tests/auto/cursor/data/sliders.qml new file mode 100644 index 00000000..408e8947 --- /dev/null +++ b/tests/auto/cursor/data/sliders.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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.2 + +MouseArea { + width: column.width + height: column.height + cursorShape: Qt.ForbiddenCursor + + Column { + id: column + padding: 10 + spacing: 10 + + Dial { + } + Slider { + } + RangeSlider { + } + } +} diff --git a/tests/auto/cursor/tst_cursor.cpp b/tests/auto/cursor/tst_cursor.cpp index dafb3159..6256112d 100644 --- a/tests/auto/cursor/tst_cursor.cpp +++ b/tests/auto/cursor/tst_cursor.cpp @@ -37,7 +37,10 @@ #include #include "../shared/visualtestutil.h" +#include #include +#include +#include #include #include @@ -48,9 +51,114 @@ class tst_cursor : public QQmlDataTest Q_OBJECT private slots: + void controls_data(); + void controls(); + void editable(); + void pageIndicator(); void scrollBar(); }; +void tst_cursor::controls_data() +{ + QTest::addColumn("testFile"); + + QTest::newRow("buttons") << "buttons.qml"; + QTest::newRow("containers") << "containers.qml"; + QTest::newRow("sliders") << "sliders.qml"; +} + +void tst_cursor::controls() +{ + QFETCH(QString, testFile); + + QQuickView view(testFileUrl(testFile)); + view.show(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickItem *mouseArea = view.rootObject(); + QVERIFY(mouseArea); + QCOMPARE(mouseArea->cursor().shape(), Qt::ForbiddenCursor); + + QQuickItem *column = mouseArea->childItems().value(0); + QVERIFY(column); + + const auto controls = column->childItems(); + for (QQuickItem *control : controls) { + QCOMPARE(control->cursor().shape(), Qt::ArrowCursor); + + QTest::mouseMove(&view, control->mapToScene(QPointF(-1, -1)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ForbiddenCursor); + + QTest::mouseMove(&view, control->mapToScene(QPointF(0, 0)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ArrowCursor); + + QTest::mouseMove(&view, control->mapToScene(QPointF(control->width() + 1, control->height() + 1)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ForbiddenCursor); + } +} + +void tst_cursor::editable() +{ + QQuickView view(testFileUrl("editable.qml")); + view.show(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickItem *mouseArea = view.rootObject(); + QVERIFY(mouseArea); + QCOMPARE(mouseArea->cursor().shape(), Qt::ForbiddenCursor); + + QQuickItem *column = mouseArea->childItems().value(0); + QVERIFY(column); + + const auto children = column->childItems(); + for (QQuickItem *child : children) { + QQuickControl *control = qobject_cast(child); + QVERIFY(control); + QCOMPARE(control->cursor().shape(), Qt::ArrowCursor); + QCOMPARE(control->contentItem()->cursor().shape(), Qt::IBeamCursor); + + QTest::mouseMove(&view, control->mapToScene(QPointF(-1, -1)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ForbiddenCursor); + + QTest::mouseMove(&view, control->mapToScene(QPointF(control->width() / 2, control->height() / 2)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::IBeamCursor); + + control->setProperty("editable", false); + QCOMPARE(control->cursor().shape(), Qt::ArrowCursor); + QCOMPARE(control->contentItem()->cursor().shape(), Qt::ArrowCursor); + QCOMPARE(view.cursor().shape(), Qt::ArrowCursor); + + QTest::mouseMove(&view, control->mapToScene(QPointF(control->width() + 1, control->height() + 1)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ForbiddenCursor); + } +} + +void tst_cursor::pageIndicator() +{ + QQuickView view(testFileUrl("pageindicator.qml")); + view.show(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickItem *mouseArea = view.rootObject(); + QVERIFY(mouseArea); + QCOMPARE(mouseArea->cursor().shape(), Qt::ForbiddenCursor); + + QQuickPageIndicator *indicator = qobject_cast(mouseArea->childItems().value(0)); + QVERIFY(indicator); + + QTest::mouseMove(&view, indicator->mapToScene(QPointF(-1, -1)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ForbiddenCursor); + + QTest::mouseMove(&view, indicator->mapToScene(QPointF(0, 0)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ForbiddenCursor); + + indicator->setInteractive(true); + QCOMPARE(view.cursor().shape(), Qt::ArrowCursor); + + QTest::mouseMove(&view, indicator->mapToScene(QPointF(indicator->width() + 1, indicator->height() + 1)).toPoint()); + QCOMPARE(view.cursor().shape(), Qt::ForbiddenCursor); +} + // QTBUG-59629 void tst_cursor::scrollBar() { @@ -59,7 +167,7 @@ void tst_cursor::scrollBar() QQuickApplicationHelper helper(this, QStringLiteral("scrollbar.qml")); QQuickApplicationWindow *window = helper.appWindow; window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowActive(window)); QQuickScrollBar *scrollBar = helper.appWindow->property("scrollBar").value(); QVERIFY(scrollBar); @@ -72,12 +180,16 @@ void tst_cursor::scrollBar() const QPoint textAreaPos(window->width() / 2, window->height() / 2); QTest::mouseMove(window, textAreaPos); QCOMPARE(window->cursor().shape(), textArea->cursor().shape()); + QCOMPARE(textArea->cursor().shape(), Qt::CursorShape::IBeamCursor); const QPoint scrollBarPos(window->width() - scrollBar->width() / 2, window->height() / 2); QTest::mouseMove(window, scrollBarPos); QVERIFY(scrollBar->isActive()); QCOMPARE(window->cursor().shape(), scrollBar->cursor().shape()); QCOMPARE(scrollBar->cursor().shape(), Qt::CursorShape::ArrowCursor); + + scrollBar->setInteractive(false); + QCOMPARE(window->cursor().shape(), textArea->cursor().shape()); } QTEST_MAIN(tst_cursor) -- cgit v1.2.3