diff options
Diffstat (limited to 'src')
44 files changed, 1493 insertions, 390 deletions
diff --git a/src/imports/controls/Container.qml b/src/imports/controls/Container.qml new file mode 100644 index 00000000..9e9215f8 --- /dev/null +++ b/src/imports/controls/Container.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.0 as T + +T.Container { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + (contentItem ? contentItem.implicitWidth : 0) + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + (contentItem ? contentItem.implicitHeight : 0) + topPadding + bottomPadding) +} diff --git a/src/imports/controls/Control.qml b/src/imports/controls/Control.qml new file mode 100644 index 00000000..a4bb95fe --- /dev/null +++ b/src/imports/controls/Control.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.0 as T + +T.Control { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + (contentItem ? contentItem.implicitWidth : 0) + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + (contentItem ? contentItem.implicitHeight : 0) + topPadding + bottomPadding) +} diff --git a/src/imports/controls/RoundButton.qml b/src/imports/controls/RoundButton.qml new file mode 100644 index 00000000..102774e0 --- /dev/null +++ b/src/imports/controls/RoundButton.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.1 as T + +T.RoundButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + padding: 6 + + //! [contentItem] + contentItem: Text { + text: control.text + font: control.font + opacity: enabled || control.highlighted || control.checked ? 1 : 0.3 + color: control.checked || control.highlighted ? "#ffffff" : (control.visualFocus ? "#0066ff" : (control.down ? "#26282a" : "#353637")) + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + //! [contentItem] + + //! [background] + background: Rectangle { + implicitWidth: 40 + implicitHeight: 40 + radius: control.radius + opacity: enabled ? 1 : 0.3 + visible: !control.flat || control.down || control.checked || control.highlighted + color: control.checked || control.highlighted ? + (control.visualFocus ? (control.down ? "#599bff" : "#0066ff") : (control.down ? "#585a5c" : "#353637")) : + (control.visualFocus ? (control.down ? "#cce0ff" : "#f0f6ff") : (control.down ? "#d0d0d0" : "#e0e0e0")) + border.color: "#0066ff" + border.width: control.visualFocus ? 2 : 0 + } + //! [background] +} diff --git a/src/imports/controls/TextField.qml b/src/imports/controls/TextField.qml index 5fdb6fc9..540a8da4 100644 --- a/src/imports/controls/TextField.qml +++ b/src/imports/controls/TextField.qml @@ -41,8 +41,10 @@ T.TextField { id: control implicitWidth: Math.max(background ? background.implicitWidth : 0, - placeholder.implicitWidth + leftPadding + rightPadding) - implicitHeight: Math.max(background ? background.implicitHeight : 0, + placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) + || contentWidth + leftPadding + rightPadding + implicitHeight: Math.max(contentHeight + topPadding + bottomPadding, + background ? background.implicitHeight : 0, placeholder.implicitHeight + topPadding + bottomPadding) padding: 6 diff --git a/src/imports/controls/controls.pri b/src/imports/controls/controls.pri index 9eeb2c1f..f84c59bc 100644 --- a/src/imports/controls/controls.pri +++ b/src/imports/controls/controls.pri @@ -16,6 +16,8 @@ QML_CONTROLS = \ CheckDelegate.qml \ CheckIndicator.qml \ ComboBox.qml \ + Container.qml \ + Control.qml \ Dial.qml \ Dialog.qml \ DialogButtonBox.qml \ @@ -36,6 +38,7 @@ QML_CONTROLS = \ RadioDelegate.qml \ RadioIndicator.qml \ RangeSlider.qml \ + RoundButton.qml \ ScrollBar.qml \ ScrollIndicator.qml \ Slider.qml \ diff --git a/src/imports/controls/doc/images/qtquickcontrols2-roundbutton.png b/src/imports/controls/doc/images/qtquickcontrols2-roundbutton.png Binary files differnew file mode 100644 index 00000000..9f1d44fc --- /dev/null +++ b/src/imports/controls/doc/images/qtquickcontrols2-roundbutton.png diff --git a/src/imports/controls/doc/snippets/qtquickcontrols2-roundbutton.qml b/src/imports/controls/doc/snippets/qtquickcontrols2-roundbutton.qml new file mode 100644 index 00000000..fa926302 --- /dev/null +++ b/src/imports/controls/doc/snippets/qtquickcontrols2-roundbutton.qml @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.1 + +//! [1] +RoundButton { + text: "\u2713" // Unicode Character 'CHECK MARK' + onClicked: textArea.readOnly = true +} +//! [1] diff --git a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc index d98b70d1..3e804bd4 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc @@ -548,6 +548,12 @@ \snippet qtquickcontrols2-rangeslider-custom.qml file + \section2 Customizing RoundButton + + RoundButton can be customized in the same manner as + \l {Customizing Button}{Button}. + + \section2 Customizing ScrollBar ScrollBar consists of two visual items: \l {Control::background}{background} diff --git a/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc index 74a7ece1..5685a852 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc @@ -39,6 +39,7 @@ \list \li \l {material-accent-attached-prop}{\b accent} : color \li \l {material-background-attached-prop}{\b background} : color + \li \l {material-elevation-attached-prop}{\b elevation} : int \li \l {material-foreground-attached-prop}{\b foreground} : color \li \l {material-primary-attached-prop}{\b primary} : color \li \l {material-theme-attached-prop}{\b theme} : enumeration @@ -280,6 +281,16 @@ \endstyleproperty + \styleproperty {Material.elevation} {int} {material-elevation-attached-prop} + \target material-elevation-attached-prop + This attached property holds the elevation of the control. The higher the + elevation, the deeper the shadow. The property can be attached to any control, + but not all controls visualize elevation. + + The default value is control-specific. + + \endstyleproperty + \styleproperty {Material.foreground} {color} {material-foreground-attached-prop} \target material-foreground-attached-prop This attached property holds the foreground color of the theme. The property diff --git a/src/imports/controls/material/RoundButton.qml b/src/imports/controls/material/RoundButton.qml new file mode 100644 index 00000000..57f30e30 --- /dev/null +++ b/src/imports/controls/material/RoundButton.qml @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.1 as T +import QtQuick.Controls.Material 2.1 +import QtQuick.Controls.Material.impl 2.1 + +T.RoundButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + // external vertical padding is 6 (to increase touch area) + padding: 12 + + hoverEnabled: Qt.styleHints.useHoverEffects + + Material.elevation: flat ? control.down || control.hovered ? 2 : 0 + : control.down ? 8 : 2 + Material.background: flat ? "transparent" : undefined + + contentItem: Text { + text: control.text + font: control.font + color: !control.enabled ? control.Material.hintTextColor : + control.flat && control.highlighted ? control.Material.accentColor : + control.highlighted ? control.Material.primaryHighlightedTextColor : control.Material.primaryTextColor + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + // TODO: Add a proper ripple/ink effect for mouse/touch input and focus state + background: Rectangle { + implicitWidth: 48 + implicitHeight: 48 + + // external vertical padding is 6 (to increase touch area) + x: 6 + y: 6 + width: parent.width - 12 + height: parent.height - 12 + radius: control.radius + color: !control.enabled ? control.Material.buttonDisabledColor + : control.checked || control.highlighted ? control.Material.highlightedButtonColor : control.Material.buttonColor + + Rectangle { + width: parent.width + height: parent.height + radius: control.radius + visible: control.hovered || control.visualFocus + color: control.Material.rippleColor + } + + Rectangle { + width: parent.width + height: parent.height + radius: control.radius + visible: control.down + color: control.Material.rippleColor + } + + Behavior on color { + ColorAnimation { + duration: 400 + } + } + + // The layer is disabled when the button color is transparent so that you can do + // Material.background: "transparent" and get a proper flat button without needing + // to set Material.elevation as well + layer.enabled: control.enabled && control.Material.buttonColor.a > 0 + layer.effect: ElevationEffect { + elevation: control.Material.elevation + } + } +} diff --git a/src/imports/controls/material/TextField.qml b/src/imports/controls/material/TextField.qml index a6406afa..25811322 100644 --- a/src/imports/controls/material/TextField.qml +++ b/src/imports/controls/material/TextField.qml @@ -42,9 +42,11 @@ T.TextField { id: control implicitWidth: Math.max(background ? background.implicitWidth : 0, - placeholder.implicitWidth + leftPadding + rightPadding) - implicitHeight: Math.max(background ? background.implicitHeight : 0, - placeholder.implicitHeight + 1 + topPadding + bottomPadding) + placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) + || contentWidth + leftPadding + rightPadding + implicitHeight: Math.max(contentHeight + topPadding + bottomPadding, + background ? background.implicitHeight : 0, + placeholder.implicitHeight + topPadding + bottomPadding) topPadding: 8 bottomPadding: 16 diff --git a/src/imports/controls/material/ToolBar.qml b/src/imports/controls/material/ToolBar.qml index ce4f64ec..0da814f1 100644 --- a/src/imports/controls/material/ToolBar.qml +++ b/src/imports/controls/material/ToolBar.qml @@ -56,7 +56,7 @@ T.ToolBar { background: Rectangle { implicitHeight: 48 - color: control.Material.primaryColor + color: control.Material.toolBarColor layer.enabled: control.Material.elevation > 0 layer.effect: ElevationEffect { diff --git a/src/imports/controls/material/material.pri b/src/imports/controls/material/material.pri index 437edeee..3170a695 100644 --- a/src/imports/controls/material/material.pri +++ b/src/imports/controls/material/material.pri @@ -42,6 +42,7 @@ QML_FILES += \ $$PWD/RadioDelegate.qml \ $$PWD/RadioIndicator.qml \ $$PWD/RangeSlider.qml \ + $$PWD/RoundButton.qml \ $$PWD/RectangularGlow.qml \ $$PWD/ScrollBar.qml \ $$PWD/ScrollIndicator.qml \ diff --git a/src/imports/controls/material/qquickmaterialstyle.cpp b/src/imports/controls/material/qquickmaterialstyle.cpp index 76332c51..0e9f31df 100644 --- a/src/imports/controls/material/qquickmaterialstyle.cpp +++ b/src/imports/controls/material/qquickmaterialstyle.cpp @@ -706,6 +706,7 @@ void QQuickMaterialStyle::setBackground(const QVariant &var) m_background = background; propagateBackground(); emit backgroundChanged(); + emit paletteChanged(); } void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool has) @@ -854,7 +855,7 @@ QColor QQuickMaterialStyle::buttonColor(bool highlighted) const QColor color = Qt::transparent; - if (m_hasBackground) { + if (m_explicitBackground) { color = backgroundColor(shade); } else if (highlighted) { color = accentColor(shade); @@ -950,16 +951,11 @@ QColor QQuickMaterialStyle::scrollBarPressedColor() const return QColor::fromRgba(m_theme == Light ? 0x80000000 : 0x80FFFFFF); } -QColor QQuickMaterialStyle::drawerBackgroundColor() const -{ - return QColor::fromRgba(dividerColorLight); -} - QColor QQuickMaterialStyle::dialogColor() const { - if (!m_hasBackground) - return QColor::fromRgba(m_theme == Light ? dialogColorLight : dialogColorDark); - return backgroundColor(); + if (m_hasBackground) + return backgroundColor(); + return QColor::fromRgba(m_theme == Light ? dialogColorLight : dialogColorDark); } QColor QQuickMaterialStyle::backgroundDimColor() const @@ -974,9 +970,18 @@ QColor QQuickMaterialStyle::listHighlightColor() const QColor QQuickMaterialStyle::tooltipColor() const { + if (m_explicitBackground) + return backgroundColor(); return color(Grey, Shade700); } +QColor QQuickMaterialStyle::toolBarColor() const +{ + if (m_explicitBackground) + return backgroundColor(); + return primaryColor(); +} + QColor QQuickMaterialStyle::toolTextColor() const { if (m_hasForeground || m_customPrimary) diff --git a/src/imports/controls/material/qquickmaterialstyle_p.h b/src/imports/controls/material/qquickmaterialstyle_p.h index 78ba88da..e6e4fe05 100644 --- a/src/imports/controls/material/qquickmaterialstyle_p.h +++ b/src/imports/controls/material/qquickmaterialstyle_p.h @@ -91,11 +91,11 @@ class QQuickMaterialStyle : public QQuickStyleAttached Q_PROPERTY(QColor scrollBarColor READ scrollBarColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor scrollBarHoveredColor READ scrollBarHoveredColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor scrollBarPressedColor READ scrollBarPressedColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor drawerBackgroundColor READ drawerBackgroundColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor dialogColor READ dialogColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor backgroundDimColor READ backgroundDimColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor listHighlightColor READ listHighlightColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor tooltipColor READ tooltipColor NOTIFY paletteChanged FINAL) + Q_PROPERTY(QColor toolBarColor READ toolBarColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor toolTextColor READ toolTextColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor spinBoxDisabledIconColor READ spinBoxDisabledIconColor NOTIFY paletteChanged FINAL) @@ -213,11 +213,11 @@ public: QColor scrollBarColor() const; QColor scrollBarHoveredColor() const; QColor scrollBarPressedColor() const; - QColor drawerBackgroundColor() const; QColor dialogColor() const; QColor backgroundDimColor() const; QColor listHighlightColor() const; QColor tooltipColor() const; + QColor toolBarColor() const; QColor toolTextColor() const; QColor spinBoxDisabledIconColor() const; diff --git a/src/imports/controls/plugins.qmltypes b/src/imports/controls/plugins.qmltypes index 0700e7bf..a1ca509b 100644 --- a/src/imports/controls/plugins.qmltypes +++ b/src/imports/controls/plugins.qmltypes @@ -16,14 +16,14 @@ Module { name: "QQuickBusyIndicatorRing" defaultProperty: "data" prototype: "QQuickItem" - exports: ["QtQuick.Controls.impl/BusyRing 2.1"] + exports: ["QtQuick.Controls.impl/BusyRing 2.0"] exportMetaObjectRevisions: [0] } Component { name: "QQuickDialRing" defaultProperty: "data" prototype: "QQuickPaintedItem" - exports: ["QtQuick.Controls.impl/DialRing 2.1"] + exports: ["QtQuick.Controls.impl/DialRing 2.0"] exportMetaObjectRevisions: [0] Property { name: "progress"; type: "double" } Property { name: "color"; type: "QColor" } @@ -32,7 +32,7 @@ Module { name: "QQuickProgressStrip" defaultProperty: "data" prototype: "QQuickItem" - exports: ["QtQuick.Controls.impl/ProgressStrip 2.1"] + exports: ["QtQuick.Controls.impl/ProgressStrip 2.0"] exportMetaObjectRevisions: [0] Property { name: "indeterminate"; type: "bool" } Property { name: "progress"; type: "double" } @@ -89,9 +89,9 @@ Module { } Component { prototype: "QQuickRectangle" - name: "QtQuick.Controls.impl/CheckIndicator 2.1" - exports: ["QtQuick.Controls.impl/CheckIndicator 2.1"] - exportMetaObjectRevisions: [1] + name: "QtQuick.Controls.impl/CheckIndicator 2.0" + exports: ["QtQuick.Controls.impl/CheckIndicator 2.0"] + exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "data" Property { name: "control"; type: "QQuickItem"; isPointer: true } @@ -105,6 +105,22 @@ Module { defaultProperty: "data" } Component { + prototype: "QQuickContainer" + name: "QtQuick.Controls/Container 2.0" + exports: ["QtQuick.Controls/Container 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickControl" + name: "QtQuick.Controls/Control 2.0" + exports: ["QtQuick.Controls/Control 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { prototype: "QQuickDial" name: "QtQuick.Controls/Dial 2.0" exports: ["QtQuick.Controls/Dial 2.0"] @@ -185,6 +201,14 @@ Module { defaultProperty: "data" } Component { + prototype: "QQuickMenuSeparator" + name: "QtQuick.Controls/MenuSeparator 2.1" + exports: ["QtQuick.Controls/MenuSeparator 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + } + Component { prototype: "QQuickPage" name: "QtQuick.Controls/Page 2.0" exports: ["QtQuick.Controls/Page 2.0"] @@ -242,9 +266,9 @@ Module { } Component { prototype: "QQuickRectangle" - name: "QtQuick.Controls.impl/RadioIndicator 2.1" - exports: ["QtQuick.Controls.impl/RadioIndicator 2.1"] - exportMetaObjectRevisions: [1] + name: "QtQuick.Controls.impl/RadioIndicator 2.0" + exports: ["QtQuick.Controls.impl/RadioIndicator 2.0"] + exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "data" Property { name: "control"; type: "QQuickItem"; isPointer: true } @@ -258,6 +282,14 @@ Module { defaultProperty: "data" } Component { + prototype: "QQuickRoundButton" + name: "QtQuick.Controls/RoundButton 2.1" + exports: ["QtQuick.Controls/RoundButton 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + } + Component { prototype: "QQuickScrollBar" name: "QtQuick.Controls/ScrollBar 2.0" exports: ["QtQuick.Controls/ScrollBar 2.0"] @@ -331,9 +363,9 @@ Module { } Component { prototype: "QQuickItem" - name: "QtQuick.Controls.impl/SwitchIndicator 2.1" - exports: ["QtQuick.Controls.impl/SwitchIndicator 2.1"] - exportMetaObjectRevisions: [1] + name: "QtQuick.Controls.impl/SwitchIndicator 2.0" + exports: ["QtQuick.Controls.impl/SwitchIndicator 2.0"] + exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "data" Property { name: "control"; type: "QQuickItem"; isPointer: true } @@ -529,11 +561,15 @@ Module { name: "QQuickComboBox" defaultProperty: "data" prototype: "QQuickControl" - exports: ["QtQuick.Templates/ComboBox 2.0"] - exportMetaObjectRevisions: [0] + exports: [ + "QtQuick.Templates/ComboBox 2.0", + "QtQuick.Templates/ComboBox 2.1" + ] + exportMetaObjectRevisions: [0, 1] Property { name: "count"; type: "int"; isReadonly: true } Property { name: "model"; type: "QVariant" } Property { name: "delegateModel"; type: "QQmlInstanceModel"; isReadonly: true; isPointer: true } + Property { name: "flat"; revision: 1; type: "bool" } Property { name: "pressed"; type: "bool" } Property { name: "highlightedIndex"; type: "int"; isReadonly: true } Property { name: "currentIndex"; type: "int" } @@ -543,6 +579,7 @@ Module { Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } Property { name: "indicator"; type: "QQuickItem"; isPointer: true } Property { name: "popup"; type: "QQuickPopup"; isPointer: true } + Signal { name: "flatChanged"; revision: 1 } Signal { name: "activated" Parameter { name: "index"; type: "int" } @@ -982,6 +1019,13 @@ Module { Signal { name: "triggered" } } Component { + name: "QQuickMenuSeparator" + defaultProperty: "data" + prototype: "QQuickControl" + exports: ["QtQuick.Templates/MenuSeparator 2.1"] + exportMetaObjectRevisions: [0] + } + Component { name: "QQuickOverlay" defaultProperty: "data" prototype: "QQuickItem" @@ -1202,6 +1246,14 @@ Module { } } Component { + name: "QQuickRoundButton" + defaultProperty: "data" + prototype: "QQuickButton" + exports: ["QtQuick.Templates/RoundButton 2.1"] + exportMetaObjectRevisions: [1] + Property { name: "radius"; type: "double" } + } + Component { name: "QQuickScrollBar" defaultProperty: "data" prototype: "QQuickControl" @@ -1333,6 +1385,7 @@ Module { Signal { name: "activating" } Signal { name: "deactivated" } Signal { name: "deactivating" } + Signal { name: "removed" } } Component { name: "QQuickStackView" diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index 3cd3b8b2..f7ee00a6 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -87,8 +87,6 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType<QQuickAbstractButton>(uri, 2, 0, "AbstractButton"); qmlRegisterType<QQuickButtonGroup>(uri, 2, 0, "ButtonGroup"); qmlRegisterType<QQuickButtonGroupAttached>(); - qmlRegisterType<QQuickContainer>(uri, 2, 0, "Container"); - qmlRegisterType<QQuickControl>(uri, 2, 0, "Control"); QQuickStylePrivate::init(typeUrl()); const QString style = QQuickStyle::name(); @@ -104,6 +102,8 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("CheckBox.qml")), uri, 2, 0, "CheckBox"); qmlRegisterType(selector.select(QStringLiteral("CheckDelegate.qml")), uri, 2, 0, "CheckDelegate"); qmlRegisterType(selector.select(QStringLiteral("ComboBox.qml")), uri, 2, 0, "ComboBox"); + qmlRegisterType(selector.select(QStringLiteral("Container.qml")), uri, 2, 0, "Container"); + qmlRegisterType(selector.select(QStringLiteral("Control.qml")), uri, 2, 0, "Control"); qmlRegisterType(selector.select(QStringLiteral("Dial.qml")), uri, 2, 0, "Dial"); qmlRegisterType(selector.select(QStringLiteral("Drawer.qml")), uri, 2, 0, "Drawer"); qmlRegisterType(selector.select(QStringLiteral("Frame.qml")), uri, 2, 0, "Frame"); @@ -144,6 +144,7 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("Dialog.qml")), uri, 2, 1, "Dialog"); qmlRegisterType(selector.select(QStringLiteral("DialogButtonBox.qml")), uri, 2, 1, "DialogButtonBox"); qmlRegisterType(selector.select(QStringLiteral("MenuSeparator.qml")), uri, 2, 1, "MenuSeparator"); + qmlRegisterType(selector.select(QStringLiteral("RoundButton.qml")), uri, 2, 1, "RoundButton"); qmlRegisterType(selector.select(QStringLiteral("ToolSeparator.qml")), uri, 2, 1, "ToolSeparator"); } diff --git a/src/imports/controls/universal/RoundButton.qml b/src/imports/controls/universal/RoundButton.qml new file mode 100644 index 00000000..61701099 --- /dev/null +++ b/src/imports/controls/universal/RoundButton.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.1 as T +import QtQuick.Controls.Universal 2.1 + +T.RoundButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + hoverEnabled: Qt.styleHints.useHoverEffects + + padding: 8 + + property bool useSystemFocusVisuals: true + + contentItem: Text { + text: control.text + font: control.font + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + opacity: enabled ? 1.0 : 0.2 + color: control.Universal.foreground + } + + background: Rectangle { + implicitWidth: 32 + implicitHeight: 32 + + radius: control.radius + visible: !control.flat || control.down || control.checked || control.highlighted + color: control.down ? control.Universal.baseMediumLowColor : + control.enabled && (control.highlighted || control.checked) ? control.Universal.accent : + control.Universal.baseLowColor + + Rectangle { + width: parent.width + height: parent.height + radius: control.radius + color: "transparent" + visible: control.hovered + border.width: 2 // ButtonBorderThemeThickness + border.color: control.Universal.baseMediumLowColor + } + } +} diff --git a/src/imports/controls/universal/TextField.qml b/src/imports/controls/universal/TextField.qml index 88bc4fc9..afa09946 100644 --- a/src/imports/controls/universal/TextField.qml +++ b/src/imports/controls/universal/TextField.qml @@ -41,9 +41,9 @@ import QtQuick.Controls.Universal 2.1 T.TextField { id: control - implicitWidth: Math.max(contentWidth + leftPadding + rightPadding, - background ? background.implicitWidth : 0, - placeholder.implicitWidth + leftPadding + rightPadding) + implicitWidth: Math.max(background ? background.implicitWidth : 0, + placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) + || contentWidth + leftPadding + rightPadding implicitHeight: Math.max(contentHeight + topPadding + bottomPadding, background ? background.implicitHeight : 0, placeholder.implicitHeight + topPadding + bottomPadding) diff --git a/src/imports/controls/universal/universal.pri b/src/imports/controls/universal/universal.pri index 72edbc32..3697a2a6 100644 --- a/src/imports/controls/universal/universal.pri +++ b/src/imports/controls/universal/universal.pri @@ -26,6 +26,7 @@ QML_FILES += \ $$PWD/RadioDelegate.qml \ $$PWD/RadioIndicator.qml \ $$PWD/RangeSlider.qml \ + $$PWD/RoundButton.qml \ $$PWD/ScrollBar.qml \ $$PWD/ScrollIndicator.qml \ $$PWD/Slider.qml \ diff --git a/src/imports/templates/plugins.qmltypes b/src/imports/templates/plugins.qmltypes index cbcc1fc7..dd991cfe 100644 --- a/src/imports/templates/plugins.qmltypes +++ b/src/imports/templates/plugins.qmltypes @@ -144,6 +144,7 @@ Module { Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } Property { name: "indicator"; type: "QQuickItem"; isPointer: true } Property { name: "popup"; type: "QQuickPopup"; isPointer: true } + Signal { name: "flatChanged"; revision: 1 } Signal { name: "activated" Parameter { name: "index"; type: "int" } @@ -583,6 +584,13 @@ Module { Signal { name: "triggered" } } Component { + name: "QQuickMenuSeparator" + defaultProperty: "data" + prototype: "QQuickControl" + exports: ["QtQuick.Templates/MenuSeparator 2.1"] + exportMetaObjectRevisions: [0] + } + Component { name: "QQuickOverlay" defaultProperty: "data" prototype: "QQuickItem" @@ -803,6 +811,14 @@ Module { } } Component { + name: "QQuickRoundButton" + defaultProperty: "data" + prototype: "QQuickButton" + exports: ["QtQuick.Templates/RoundButton 2.1"] + exportMetaObjectRevisions: [1] + Property { name: "radius"; type: "double" } + } + Component { name: "QQuickScrollBar" defaultProperty: "data" prototype: "QQuickControl" @@ -934,6 +950,7 @@ Module { Signal { name: "activating" } Signal { name: "deactivated" } Signal { name: "deactivating" } + Signal { name: "removed" } } Component { name: "QQuickStackView" diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index 67a52d14..6624b019 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -66,6 +66,7 @@ #include <QtQuickTemplates2/private/qquickradiobutton_p.h> #include <QtQuickTemplates2/private/qquickradiodelegate_p.h> #include <QtQuickTemplates2/private/qquickrangeslider_p.h> +#include <QtQuickTemplates2/private/qquickroundbutton_p.h> #include <QtQuickTemplates2/private/qquickscrollbar_p.h> #include <QtQuickTemplates2/private/qquickscrollindicator_p.h> #include <QtQuickTemplates2/private/qquickslider_p.h> @@ -186,6 +187,7 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri) qmlRegisterType<QQuickMenuSeparator>(uri, 2, 1, "MenuSeparator"); qmlRegisterType<QQuickPopup, 1>(uri, 2, 1, "Popup"); qmlRegisterType<QQuickRangeSlider, 1>(uri, 2, 1, "RangeSlider"); + qmlRegisterType<QQuickRoundButton, 1>(uri, 2, 1, "RoundButton"); qmlRegisterType<QQuickSlider, 1>(uri, 2, 1, "Slider"); qmlRegisterType<QQuickSpinBox, 1>(uri, 2, 1, "SpinBox"); qmlRegisterType<QQuickStackView, 1>(uri, 2, 1, "StackView"); diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp index bee837e9..ca5beafe 100644 --- a/src/quickcontrols2/qquickstyle.cpp +++ b/src/quickcontrols2/qquickstyle.cpp @@ -109,6 +109,24 @@ struct QQuickStyleSpec resolve(); } + static QString findStyle(const QString &path, const QString &name) + { + QDir dir(path); + if (!dir.exists()) + return QString(); + + if (name.isEmpty()) + return dir.absolutePath() + QLatin1Char('/'); + + const QStringList entries = dir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &entry : entries) { + if (entry.compare(name, Qt::CaseInsensitive) == 0) + return dir.absoluteFilePath(entry); + } + + return QString(); + } + void resolve(const QUrl &baseUrl = QUrl()) { if (style.isEmpty()) @@ -122,10 +140,12 @@ struct QQuickStyleSpec } if (baseUrl.isValid()) { - if (style.isEmpty()) - style = baseUrl.toString(QUrl::StripTrailingSlash) + QLatin1Char('/'); - else if (!style.contains(QLatin1Char('/'))) - style = baseUrl.toString(QUrl::StripTrailingSlash) + QLatin1Char('/') + style; + QString path = QQmlFile::urlToLocalFileOrQrc(baseUrl); + QString stylePath = findStyle(path, style); + if (!stylePath.isEmpty()) { + style = stylePath; + resolved = true; + } } if (QGuiApplication::instance()) { @@ -134,24 +154,12 @@ struct QQuickStyleSpec const QStringList importPaths = QQmlEngine().importPathList(); for (const QString &importPath : importPaths) { - QDir importDir(importPath); - if (importDir.cd(targetPath)) { - if (style.isEmpty()) { - style = importDir.absolutePath() + QLatin1Char('/'); - resolved = true; - break; - } - const QStringList entries = importDir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &entry : entries) { - if (entry.compare(style, Qt::CaseInsensitive) == 0) { - style = importDir.absoluteFilePath(entry); - resolved = true; - break; - } - } - } - if (resolved) + QString stylePath = findStyle(importPath + QLatin1Char('/') + targetPath, style); + if (!stylePath.isEmpty()) { + style = stylePath; + resolved = true; break; + } } } resolved = true; diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index af14ba6f..7f466fd7 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -158,12 +158,6 @@ void QQuickApplicationWindowPrivate::relayout() content->setWidth(q->width()); content->setHeight(q->height() - hh - fh); - if (overlay) { - overlay->setWidth(q->width()); - overlay->setHeight(q->height()); - overlay->stackAfter(content); - } - if (header) { header->setY(-hh); QQuickItemPrivate *p = QQuickItemPrivate::get(header); @@ -489,9 +483,12 @@ QQuickItem *QQuickApplicationWindow::activeFocusControl() const QQuickOverlay *QQuickApplicationWindow::overlay() const { QQuickApplicationWindowPrivate *d = const_cast<QQuickApplicationWindowPrivate *>(d_func()); + if (!d) // being deleted + return nullptr; + if (!d->overlay) { d->overlay = new QQuickOverlay(QQuickWindow::contentItem()); - d->relayout(); + d->overlay->stackAfter(QQuickApplicationWindow::contentItem()); } return d->overlay; } diff --git a/src/quicktemplates2/qquickbutton.cpp b/src/quicktemplates2/qquickbutton.cpp index a51e2210..19310713 100644 --- a/src/quicktemplates2/qquickbutton.cpp +++ b/src/quicktemplates2/qquickbutton.cpp @@ -35,7 +35,7 @@ ****************************************************************************/ #include "qquickbutton_p.h" -#include "qquickabstractbutton_p_p.h" +#include "qquickbutton_p_p.h" #include <QtGui/qpa/qplatformtheme.h> @@ -91,17 +91,6 @@ QT_BEGIN_NAMESPACE \sa {Customizing Button}, {Button Controls} */ -class QQuickButtonPrivate : public QQuickAbstractButtonPrivate -{ - Q_DECLARE_PUBLIC(QQuickButton) - -public: - QQuickButtonPrivate(); - - bool flat; - bool highlighted; -}; - QQuickButtonPrivate::QQuickButtonPrivate() : flat(false), highlighted(false) { @@ -112,6 +101,11 @@ QQuickButton::QQuickButton(QQuickItem *parent) : { } +QQuickButton::QQuickButton(QQuickButtonPrivate &dd, QQuickItem *parent) : + QQuickAbstractButton(dd, parent) +{ +} + /*! \qmlproperty bool QtQuick.Controls::Button::checkable diff --git a/src/quicktemplates2/qquickbutton_p.h b/src/quicktemplates2/qquickbutton_p.h index fafce150..95f94f10 100644 --- a/src/quicktemplates2/qquickbutton_p.h +++ b/src/quicktemplates2/qquickbutton_p.h @@ -78,6 +78,8 @@ Q_SIGNALS: void flatChanged(); protected: + QQuickButton(QQuickButtonPrivate &dd, QQuickItem *parent); + void checkableChange() override; void autoRepeatChange() override; diff --git a/src/quicktemplates2/qquickbutton_p_p.h b/src/quicktemplates2/qquickbutton_p_p.h new file mode 100644 index 00000000..86663e9e --- /dev/null +++ b/src/quicktemplates2/qquickbutton_p_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKBUTTON_P_P_H +#define QQUICKBUTTON_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickButtonPrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickButton) + +public: + QQuickButtonPrivate(); + + bool flat; + bool highlighted; +}; + +QT_END_NAMESPACE + +#endif // QQUICKBUTTON_P_P_H diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index e2e6c84e..a64b5f4e 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -35,8 +35,7 @@ ****************************************************************************/ #include "qquickdrawer_p.h" -#include "qquickpopup_p_p.h" -#include "qquickvelocitycalculator_p_p.h" +#include "qquickdrawer_p_p.h" #include <QtGui/qstylehints.h> #include <QtGui/private/qguiapplication_p.h> @@ -114,33 +113,11 @@ QT_BEGIN_NAMESPACE \sa SwipeView, {Customizing Drawer}, {Navigation Controls}, {Popup Controls} */ -class QQuickDrawerPrivate : public QQuickPopupPrivate +QQuickDrawerPrivate::QQuickDrawerPrivate() + : edge(Qt::LeftEdge), offset(0), position(0), + dragMargin(QGuiApplication::styleHints()->startDragDistance()) { - Q_DECLARE_PUBLIC(QQuickDrawer) - -public: - QQuickDrawerPrivate() : edge(Qt::LeftEdge), offset(0), position(0), - dragMargin(QGuiApplication::styleHints()->startDragDistance()) { } - - qreal positionAt(const QPointF &point) const; - void reposition() override; - - bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); - bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); - bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); - - void prepareEnterTransition(bool notify = true) override; - void prepareExitTransition() override; - void finalizeEnterTransition() override; - void finalizeExitTransition(bool hide = true) override; - - Qt::Edge edge; - qreal offset; - qreal position; - qreal dragMargin; - QPointF pressPoint; - QQuickVelocityCalculator velocityCalculator; -}; +} qreal QQuickDrawerPrivate::positionAt(const QPointF &point) const { @@ -191,100 +168,94 @@ static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int th return QQuickWindowPrivate::dragOverThreshold(d, axis, event, threshold); } -bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) +bool QQuickDrawerPrivate::startDrag(QQuickWindow *window, QMouseEvent *event) { - pressPoint = event->windowPos(); - offset = 0; - - QQuickWindow *window = item->window(); - if (!window) + if (!window || dragMargin < 0.0 || qFuzzyIsNull(dragMargin)) return false; - if (qFuzzyIsNull(position)) { - // only accept pressing at drag margins when fully closed - switch (edge) { - case Qt::LeftEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(event->windowPos().x(), Qt::XAxis, event, dragMargin)); - break; - case Qt::RightEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(window->width() - event->windowPos().x(), Qt::XAxis, event, dragMargin)); - break; - case Qt::TopEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(event->windowPos().y(), Qt::YAxis, event, dragMargin)); - break; - case Qt::BottomEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(window->height() - event->windowPos().y(), Qt::YAxis, event, dragMargin)); - break; - } - } else { - if (modal) - event->setAccepted(item->isAncestorOf(popupItem)); - else - event->setAccepted(false); + bool drag = false; + switch (edge) { + case Qt::LeftEdge: + drag = !dragOverThreshold(event->windowPos().x(), Qt::XAxis, event, dragMargin); + break; + case Qt::RightEdge: + drag = !dragOverThreshold(window->width() - event->windowPos().x(), Qt::XAxis, event, dragMargin); + break; + case Qt::TopEdge: + drag = !dragOverThreshold(event->windowPos().y(), Qt::YAxis, event, dragMargin); + break; + case Qt::BottomEdge: + drag = !dragOverThreshold(window->height() - event->windowPos().y(), Qt::YAxis, event, dragMargin); + break; + default: + break; } - velocityCalculator.startMeasuring(pressPoint, event->timestamp()); + if (drag) { + prepareEnterTransition(); + reposition(); + handleMousePressEvent(window->contentItem(), event); + } - return event->isAccepted(); + return drag; } -bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) +bool QQuickDrawerPrivate::grabMouse(QMouseEvent *event) { Q_Q(QQuickDrawer); - QQuickWindow *window = item->window(); - if (!window) + if (!window || popupItem->keepMouseGrab()) return false; - QPointF movePoint = event->windowPos(); - - if (!popupItem->keepMouseGrab()) { - // Flickable uses a hard-coded threshold of 15 for flicking, and - // QStyleHints::startDragDistance for dragging. Drawer uses a bit - // larger threshold to avoid being too eager to steal touch (QTBUG-50045) - int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5); - bool overThreshold = false; - if (position > 0 || dragMargin > 0) { - if (edge == Qt::LeftEdge || edge == Qt::RightEdge) - overThreshold = dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, event, threshold); - else - overThreshold = dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, event, threshold); - } - - // Don't be too eager to steal presses outside the drawer (QTBUG-53929) - if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !popupItem->contains(popupItem->mapFromScene(movePoint))) { - if (edge == Qt::LeftEdge || edge == Qt::RightEdge) - overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin; - else - overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin; - } + const QPointF movePoint = event->windowPos(); - if (overThreshold) { - QQuickItem *grabber = window->mouseGrabberItem(); - if (!grabber || !grabber->keepMouseGrab()) { - popupItem->grabMouse(); - popupItem->setKeepMouseGrab(overThreshold); - offset = qMin<qreal>(0.0, positionAt(movePoint) - position); - } - } + // Flickable uses a hard-coded threshold of 15 for flicking, and + // QStyleHints::startDragDistance for dragging. Drawer uses a bit + // larger threshold to avoid being too eager to steal touch (QTBUG-50045) + const int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5); + bool overThreshold = false; + if (position > 0 || dragMargin > 0) { + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) + overThreshold = dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, event, threshold); + else + overThreshold = dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, event, threshold); } - if (popupItem->keepMouseGrab()) - q->setPosition(positionAt(movePoint) - offset); - event->accept(); + // Don't be too eager to steal presses outside the drawer (QTBUG-53929) + if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !popupItem->contains(popupItem->mapFromScene(movePoint))) { + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) + overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin; + else + overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin; + } - return popupItem->keepMouseGrab(); + return overThreshold; } static const qreal openCloseVelocityThreshold = 300; -bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event) +bool QQuickDrawerPrivate::ungrabMouse(QMouseEvent *event) { - Q_UNUSED(item); - bool wasGrabbed = popupItem->keepMouseGrab(); if (wasGrabbed) { - velocityCalculator.stopMeasuring(event->pos(), event->timestamp()); - const qreal velocity = velocityCalculator.velocity().x(); + const QPointF releasePoint = event->windowPos(); + velocityCalculator.stopMeasuring(releasePoint, event->timestamp()); + + qreal velocity = 0; + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) + velocity = velocityCalculator.velocity().x(); + else + velocity = velocityCalculator.velocity().y(); + + // the velocity is calculated so that swipes from left to right + // and top to bottom have positive velocity, and swipes from right + // to left and bottom to top have negative velocity. + // + // - top/left edge: positive velocity opens, negative velocity closes + // - bottom/right edge: negative velocity opens, positive velocity closes + // + // => invert the velocity for bottom and right edges, for the threshold comparison below + if (edge == Qt::RightEdge || edge == Qt::BottomEdge) + velocity = -velocity; if (position > 0.7 || velocity > openCloseVelocityThreshold) { transitionManager.transitionEnter(); @@ -293,35 +264,79 @@ bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent } else { switch (edge) { case Qt::LeftEdge: - if (event->x() - pressPoint.x() > 0) + if (releasePoint.x() - pressPoint.x() > 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); break; case Qt::RightEdge: - if (event->x() - pressPoint.x() < 0) + if (releasePoint.x() - pressPoint.x() < 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); break; case Qt::TopEdge: - if (event->y() - pressPoint.y() > 0) + if (releasePoint.y() - pressPoint.y() > 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); break; case Qt::BottomEdge: - if (event->y() - pressPoint.y() < 0) + if (releasePoint.y() - pressPoint.y() < 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); break; } } - popupItem->setKeepMouseGrab(false); } + return wasGrabbed; +} + +bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) +{ + offset = 0; + pressPoint = event->windowPos(); + velocityCalculator.startMeasuring(pressPoint, event->timestamp()); + + // don't block press events a) outside a non-modal drawer, or b) to drawer children + event->setAccepted(modal && !popupItem->isAncestorOf(item)); + return event->isAccepted(); +} + +bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_Q(QQuickDrawer); + Q_UNUSED(item); + + const QPointF movePoint = event->windowPos(); + + if (grabMouse(event)) { + QQuickItem *grabber = window->mouseGrabberItem(); + if (!grabber || !grabber->keepMouseGrab()) { + popupItem->grabMouse(); + popupItem->setKeepMouseGrab(true); + offset = qMin<qreal>(0.0, positionAt(movePoint) - position); + } + } + + if (popupItem->keepMouseGrab()) + q->setPosition(positionAt(movePoint) - offset); + event->accept(); + + return popupItem->keepMouseGrab(); +} + +bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_UNUSED(item); + + const bool wasGrabbed = ungrabMouse(event); + + popupItem->setKeepMouseGrab(false); pressPoint = QPoint(); event->accept(); + return wasGrabbed; } @@ -345,28 +360,18 @@ static QList<QQuickStateAction> prepareTransition(QQuickDrawer *drawer, QQuickTr return actions; } -void QQuickDrawerPrivate::prepareEnterTransition(bool notify) +bool QQuickDrawerPrivate::prepareEnterTransition() { Q_Q(QQuickDrawer); enterActions = prepareTransition(q, enter, 1.0); - QQuickPopupPrivate::prepareEnterTransition(notify); + return QQuickPopupPrivate::prepareEnterTransition(); } -void QQuickDrawerPrivate::prepareExitTransition() +bool QQuickDrawerPrivate::prepareExitTransition() { Q_Q(QQuickDrawer); exitActions = prepareTransition(q, exit, 0.0); - QQuickPopupPrivate::prepareExitTransition(); -} - -void QQuickDrawerPrivate::finalizeEnterTransition() -{ - QQuickPopupPrivate::finalizeEnterTransition(); -} - -void QQuickDrawerPrivate::finalizeExitTransition(bool hide) -{ - QQuickPopupPrivate::finalizeExitTransition(hide = false); + return QQuickPopupPrivate::prepareExitTransition(); } QQuickDrawer::QQuickDrawer(QObject *parent) : @@ -430,12 +435,8 @@ void QQuickDrawer::setPosition(qreal position) d->position = position; if (isComponentComplete()) d->reposition(); - if (d->dimmer) { + if (d->dimmer) d->dimmer->setOpacity(position); - // TODO: check QStyleHints::useHoverEffects in Qt 5.8 - d->dimmer->setAcceptHoverEvents(d->modal && position > 0.0); - // d->dimmer->setAcceptHoverEvents(d->modal && position > 0.0 && QGuiApplication::styleHints()->useHoverEffects()); - } emit positionChanged(); } @@ -530,15 +531,4 @@ bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event) } } -void QQuickDrawer::componentComplete() -{ - Q_D(QQuickDrawer); - QQuickPopup::componentComplete(); - if (d->window) { - bool notify = false; - d->prepareEnterTransition(notify); - d->reposition(); - } -} - QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickdrawer_p.h b/src/quicktemplates2/qquickdrawer_p.h index 23c5c2ab..e694e27b 100644 --- a/src/quicktemplates2/qquickdrawer_p.h +++ b/src/quicktemplates2/qquickdrawer_p.h @@ -87,8 +87,6 @@ protected: void mouseUngrabEvent() override; bool overlayEvent(QQuickItem *item, QEvent *event) override; - void componentComplete() 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 new file mode 100644 index 00000000..f14c36dd --- /dev/null +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKDRAWER_P_P_H +#define QQUICKDRAWER_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdrawer_p.h" +#include "qquickpopup_p_p.h" +#include "qquickvelocitycalculator_p_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickDrawerPrivate : public QQuickPopupPrivate +{ + Q_DECLARE_PUBLIC(QQuickDrawer) + +public: + QQuickDrawerPrivate(); + + static QQuickDrawerPrivate *get(QQuickDrawer *drawer) + { + return drawer->d_func(); + } + + qreal positionAt(const QPointF &point) const; + void reposition() override; + + bool startDrag(QQuickWindow *window, QMouseEvent *event); + bool grabMouse(QMouseEvent *event); + bool ungrabMouse(QMouseEvent *event); + + bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); + + bool prepareEnterTransition() override; + bool prepareExitTransition() override; + + Qt::Edge edge; + qreal offset; + qreal position; + qreal dragMargin; + QPointF pressPoint; + QQuickVelocityCalculator velocityCalculator; +}; + +QT_END_NAMESPACE + +#endif // QQUICKDRAWER_P_P_H diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index 850de875..172307e1 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -35,39 +35,17 @@ ****************************************************************************/ #include "qquickoverlay_p.h" +#include "qquickoverlay_p_p.h" #include "qquickpopup_p_p.h" -#include "qquickdrawer_p.h" +#include "qquickdrawer_p_p.h" +#include "qquickapplicationwindow_p.h" #include <QtQml/qqmlinfo.h> #include <QtQml/qqmlproperty.h> #include <QtQml/qqmlcomponent.h> -#include <QtQuick/private/qquickitem_p.h> +#include <algorithm> QT_BEGIN_NAMESPACE -class QQuickOverlayPrivate : public QQuickItemPrivate -{ - Q_DECLARE_PUBLIC(QQuickOverlay) - -public: - QQuickOverlayPrivate(); - - void popupAboutToShow(); - void popupAboutToHide(); - - void createOverlay(QQuickPopup *popup); - void destroyOverlay(QQuickPopup *popup); - void resizeOverlay(QQuickPopup *popup); - - QVector<QQuickPopup *> stackingOrderPopups() const; - - QQmlComponent *modal; - QQmlComponent *modeless; - QVector<QQuickDrawer *> drawers; - QVector<QQuickPopup *> popups; - QPointer<QQuickPopup> mouseGrabberPopup; - int modalPopups; -}; - void QQuickOverlayPrivate::popupAboutToShow() { Q_Q(QQuickOverlay); @@ -96,27 +74,35 @@ void QQuickOverlayPrivate::popupAboutToHide() static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent) { - if (!component) - return nullptr; + QQuickItem *item = nullptr; + if (component) { + QQmlContext *creationContext = component->creationContext(); + if (!creationContext) + creationContext = qmlContext(parent); + QQmlContext *context = new QQmlContext(creationContext); + context->setContextObject(popup); + item = qobject_cast<QQuickItem*>(component->beginCreate(context)); + } + + // when there is no overlay component available (with plain QQuickWindow), + // use a plain QQuickItem as a fallback to block hover events + if (!item && popup->isModal()) + item = new QQuickItem; - QQmlContext *creationContext = component->creationContext(); - if (!creationContext) - creationContext = qmlContext(parent); - QQmlContext *context = new QQmlContext(creationContext); - context->setContextObject(popup); - QQuickItem *item = qobject_cast<QQuickItem*>(component->beginCreate(context)); if (item) { - item->setOpacity(0.0); + item->setOpacity(popup->isVisible() ? 1.0 : 0.0); item->setParentItem(parent); item->stackBefore(popup->popupItem()); item->setZ(popup->z()); - if (popup->isModal() && !qobject_cast<QQuickDrawer *>(popup)) { + if (popup->isModal()) { + item->setAcceptedMouseButtons(Qt::AllButtons); // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 item->setAcceptHoverEvents(true); // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents); } - component->completeCreate(); + if (component) + component->completeCreate(); } return item; } @@ -150,6 +136,18 @@ void QQuickOverlayPrivate::resizeOverlay(QQuickPopup *popup) } } +void QQuickOverlayPrivate::toggleOverlay() +{ + Q_Q(QQuickOverlay); + QQuickPopup *popup = qobject_cast<QQuickPopup *>(q->sender()); + if (!popup) + return; + + destroyOverlay(popup); + if (popup->dim()) + createOverlay(popup); +} + QVector<QQuickPopup *> QQuickOverlayPrivate::stackingOrderPopups() const { const QList<QQuickItem *> children = paintOrderChildItems(); @@ -166,20 +164,65 @@ QVector<QQuickPopup *> QQuickOverlayPrivate::stackingOrderPopups() const return popups; } +QVector<QQuickDrawer *> QQuickOverlayPrivate::stackingOrderDrawers() const +{ + QVector<QQuickDrawer *> sorted(allDrawers); + std::sort(sorted.begin(), sorted.end(), [](const QQuickDrawer *one, const QQuickDrawer *another) { + return one->z() > another->z(); + }); + return sorted; +} + +void QQuickOverlayPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &) +{ + Q_Q(QQuickOverlay); + q->setSize(QSizeF(item->width(), item->height())); +} + QQuickOverlayPrivate::QQuickOverlayPrivate() : modal(nullptr), - modeless(nullptr), - modalPopups(0) + modeless(nullptr) { } +void QQuickOverlayPrivate::addPopup(QQuickPopup *popup) +{ + Q_Q(QQuickOverlay); + allPopups += popup; + if (QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup)) { + allDrawers += drawer; + q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty()); + } +} + +void QQuickOverlayPrivate::removePopup(QQuickPopup *popup) +{ + Q_Q(QQuickOverlay); + allPopups.removeOne(popup); + if (allDrawers.removeOne(static_cast<QQuickDrawer *>(popup))) + q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty()); +} + QQuickOverlay::QQuickOverlay(QQuickItem *parent) : QQuickItem(*(new QQuickOverlayPrivate), parent) { + Q_D(QQuickOverlay); setZ(1000001); // DefaultWindowDecoration+1 setAcceptedMouseButtons(Qt::AllButtons); setFiltersChildMouseEvents(true); setVisible(false); + + if (parent) { + setSize(QSizeF(parent->width(), parent->height())); + QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry); + } +} + +QQuickOverlay::~QQuickOverlay() +{ + Q_D(QQuickOverlay); + if (QQuickItem *parent = parentItem()) + QQuickItemPrivate::get(parent)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); } QQmlComponent *QQuickOverlay::modal() const @@ -216,6 +259,29 @@ void QQuickOverlay::setModeless(QQmlComponent *modeless) emit modelessChanged(); } +QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window) +{ + if (!window) + return nullptr; + + QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow *>(window); + if (applicationWindow) + return applicationWindow->overlay(); + + const char *name = "_q_QQuickOverlay"; + QQuickOverlay *overlay = window->property(name).value<QQuickOverlay *>(); + if (!overlay) { + QQuickItem *content = window->contentItem(); + // Do not re-create the overlay if the window is being destroyed + // and thus, its content item no longer has a window associated. + if (content->window()) { + overlay = new QQuickOverlay(window->contentItem()); + window->setProperty(name, QVariant::fromValue(overlay)); + } + } + return overlay; +} + void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) { Q_D(QQuickOverlay); @@ -224,37 +290,25 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) QQuickPopup *popup = nullptr; if (change == ItemChildAddedChange || change == ItemChildRemovedChange) { popup = qobject_cast<QQuickPopup *>(data.item->parent()); - setVisible(!childItems().isEmpty()); + setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty()); } if (!popup) return; if (change == ItemChildAddedChange) { - d->popups.append(popup); if (popup->dim()) d->createOverlay(popup); - - QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup); - if (drawer) { - d->drawers.append(drawer); - } else { - if (popup->isModal()) - ++d->modalPopups; - + QObjectPrivate::connect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); + QObjectPrivate::connect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); + if (!qobject_cast<QQuickDrawer *>(popup)) { QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } } else if (change == ItemChildRemovedChange) { - d->popups.removeOne(popup); d->destroyOverlay(popup); - - QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup); - if (drawer) { - d->drawers.removeOne(drawer); - } else { - if (popup->isModal()) - --d->modalPopups; - + QObjectPrivate::disconnect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); + QObjectPrivate::disconnect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); + if (!qobject_cast<QQuickDrawer *>(popup)) { QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } @@ -265,79 +319,86 @@ void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &old { Q_D(QQuickOverlay); QQuickItem::geometryChanged(newGeometry, oldGeometry); - for (QQuickPopup *popup : d->popups) + for (QQuickPopup *popup : qAsConst(d->allPopups)) d->resizeOverlay(popup); } -bool QQuickOverlay::event(QEvent *event) +void QQuickOverlay::mousePressEvent(QMouseEvent *event) { Q_D(QQuickOverlay); - switch (event->type()) { - case QEvent::MouseButtonPress: { - emit pressed(); + emit pressed(); + + if (!d->allDrawers.isEmpty()) { + // the overlay background was pressed, so there are no modal popups open. + // test if the press point lands on any drawer's drag margin + + const QVector<QQuickDrawer *> drawers = d->stackingOrderDrawers(); + for (QQuickDrawer *drawer : drawers) { + QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer); + if (p->startDrag(window(), event)) { + d->mouseGrabberPopup = drawer; + return; + } + } + } + + if (!d->mouseGrabberPopup) { const auto popups = d->stackingOrderPopups(); for (QQuickPopup *popup : popups) { if (popup->overlayEvent(this, event)) { d->mouseGrabberPopup = popup; - return true; + return; } } - break; } - case QEvent::MouseMove: - if (d->mouseGrabberPopup) { - if (d->mouseGrabberPopup->overlayEvent(this, event)) - return true; - } else { - const auto popups = d->stackingOrderPopups(); - for (QQuickPopup *popup : popups) { - if (popup->overlayEvent(this, event)) - return true; - } - } - break; - case QEvent::MouseButtonRelease: - emit released(); - if (d->mouseGrabberPopup) { - QQuickPopup *grabber = d->mouseGrabberPopup; - d->mouseGrabberPopup = nullptr; - if (grabber->overlayEvent(this, event)) - return true; - } else { - const auto popups = d->stackingOrderPopups(); - for (QQuickPopup *popup : popups) { - if (popup->overlayEvent(this, event)) - return true; - } + + event->ignore(); +} + +void QQuickOverlay::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickOverlay); + if (d->mouseGrabberPopup) + d->mouseGrabberPopup->overlayEvent(this, event); +} + +void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickOverlay); + emit released(); + + if (d->mouseGrabberPopup) { + d->mouseGrabberPopup->overlayEvent(this, event); + d->mouseGrabberPopup = nullptr; + } else { + const auto popups = d->stackingOrderPopups(); + for (QQuickPopup *popup : popups) { + if (popup->overlayEvent(this, event)) + break; } - break; - default: - break; } - - return QQuickItem::event(event); } bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) { Q_D(QQuickOverlay); - if (d->modalPopups == 0) - return false; - // TODO Filter touch events - if (event->type() != QEvent::MouseButtonPress) - return false; - while (item->parentItem() != this) - item = item->parentItem(); - - const auto popups = d->stackingOrderPopups(); - for (QQuickPopup *popup : popups) { - if (popup->popupItem() == item) - break; - - if (popup->overlayEvent(item, event)) - return true; + for (QQuickPopup *popup : qAsConst(d->allPopups)) { + QQuickItem *dimmer = QQuickPopupPrivate::get(popup)->dimmer; + if (item == dimmer) { + switch (event->type()) { + case QEvent::MouseButtonPress: + emit pressed(); + return popup->overlayEvent(item, event); + case QEvent::MouseMove: + return popup->overlayEvent(item, event); + case QEvent::MouseButtonRelease: + emit released(); + return popup->overlayEvent(item, event); + default: + break; + } + } } - return false; } diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h index 99d7ba75..07f7daec 100644 --- a/src/quicktemplates2/qquickoverlay_p.h +++ b/src/quicktemplates2/qquickoverlay_p.h @@ -64,6 +64,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickOverlay : public QQuickItem public: explicit QQuickOverlay(QQuickItem *parent = nullptr); + ~QQuickOverlay(); QQmlComponent *modal() const; void setModal(QQmlComponent *modal); @@ -71,6 +72,8 @@ public: QQmlComponent *modeless() const; void setModeless(QQmlComponent *modeless); + static QQuickOverlay *overlay(QQuickWindow *window); + Q_SIGNALS: void modalChanged(); void modelessChanged(); @@ -81,7 +84,9 @@ protected: void itemChange(ItemChange change, const ItemChangeData &data) override; void geometryChanged(const QRectF &oldGeometry, const QRectF &newGeometry) override; - bool event(QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; private: diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h new file mode 100644 index 00000000..db005555 --- /dev/null +++ b/src/quicktemplates2/qquickoverlay_p_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKOVERLAY_P_P_H +#define QQUICKOVERLAY_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickoverlay_p.h" + +#include <QtQuick/private/qquickitem_p.h> +#include <QtQuick/private/qquickitemchangelistener_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickPopup; +class QQuickDrawer; + +class QQuickOverlayPrivate : public QQuickItemPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickOverlay) + +public: + QQuickOverlayPrivate(); + + static QQuickOverlayPrivate *get(QQuickOverlay *overlay) + { + return overlay->d_func(); + } + + void addPopup(QQuickPopup *popup); + void removePopup(QQuickPopup *popup); + + void popupAboutToShow(); + void popupAboutToHide(); + + void createOverlay(QQuickPopup *popup); + void destroyOverlay(QQuickPopup *popup); + void resizeOverlay(QQuickPopup *popup); + void toggleOverlay(); + + QVector<QQuickPopup *> stackingOrderPopups() const; + QVector<QQuickDrawer *> stackingOrderDrawers() const; + + void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override; + + QQmlComponent *modal; + QQmlComponent *modeless; + QVector<QQuickPopup *> allPopups; + QVector<QQuickDrawer *> allDrawers; + QPointer<QQuickPopup> mouseGrabberPopup; +}; + +QT_END_NAMESPACE + +#endif // QQUICKOVERLAY_P_P_H diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 414ba782..4143ee3f 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -37,7 +37,7 @@ #include "qquickpopup_p.h" #include "qquickpopup_p_p.h" #include "qquickapplicationwindow_p.h" -#include "qquickoverlay_p.h" +#include "qquickoverlay_p_p.h" #include "qquickcontrol_p_p.h" #include <QtQml/qqmlinfo.h> @@ -143,6 +143,7 @@ QQuickPopupPrivate::QQuickPopupPrivate() , bottomMargin(0) , contentWidth(0) , contentHeight(0) + , transitionState(QQuickPopupPrivate::NoTransition) , closePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside) , parentItem(nullptr) , dimmer(nullptr) @@ -180,43 +181,46 @@ bool QQuickPopupPrivate::tryClose(QQuickItem *item, QMouseEvent *event) return false; } -void QQuickPopupPrivate::prepareEnterTransition(bool notify) +bool QQuickPopupPrivate::prepareEnterTransition() { Q_Q(QQuickPopup); if (!window) { qmlInfo(q) << "cannot find any window to open popup in."; - return; + return false; } - QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow*>(window); - if (!applicationWindow) { - window->installEventFilter(q); - popupItem->setZ(1000001); // DefaultWindowDecoration+1 - popupItem->setParentItem(window->contentItem()); - } else { - popupItem->setParentItem(applicationWindow->overlay()); - } + if (transitionState == EnterTransition && transitionManager.isRunning()) + return false; - if (notify) + if (transitionState != EnterTransition) { + popupItem->setParentItem(QQuickOverlay::overlay(window)); emit q->aboutToShow(); - visible = notify; - popupItem->setVisible(true); - positioner.setParentItem(parentItem); - emit q->visibleChanged(); + visible = true; + transitionState = EnterTransition; + popupItem->setVisible(true); + positioner.setParentItem(parentItem); + emit q->visibleChanged(); + } + return true; } -void QQuickPopupPrivate::prepareExitTransition() +bool QQuickPopupPrivate::prepareExitTransition() { Q_Q(QQuickPopup); - if (window && !qobject_cast<QQuickApplicationWindow *>(window)) - window->removeEventFilter(q); - if (focus) { - // The setFocus(false) call below removes any active focus before we're - // able to check it in finalizeExitTransition. - hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); - popupItem->setFocus(false); + if (transitionState == ExitTransition && transitionManager.isRunning()) + return false; + + if (transitionState != ExitTransition) { + if (focus) { + // The setFocus(false) call below removes any active focus before we're + // able to check it in finalizeExitTransition. + hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); + popupItem->setFocus(false); + } + transitionState = ExitTransition; + emit q->aboutToHide(); } - emit q->aboutToHide(); + return true; } void QQuickPopupPrivate::finalizeEnterTransition() @@ -224,17 +228,16 @@ void QQuickPopupPrivate::finalizeEnterTransition() Q_Q(QQuickPopup); if (focus) popupItem->setFocus(true); + transitionState = NoTransition; emit q->opened(); } -void QQuickPopupPrivate::finalizeExitTransition(bool hide) +void QQuickPopupPrivate::finalizeExitTransition() { Q_Q(QQuickPopup); - if (hide) { - positioner.setParentItem(nullptr); - popupItem->setParentItem(nullptr); - popupItem->setVisible(false); - } + positioner.setParentItem(nullptr); + popupItem->setParentItem(nullptr); + popupItem->setVisible(false); if (hadActiveFocusBeforeExitTransition) { QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow*>(window); @@ -245,6 +248,7 @@ void QQuickPopupPrivate::finalizeExitTransition(bool hide) } visible = false; + transitionState = NoTransition; hadActiveFocusBeforeExitTransition = false; emit q->visibleChanged(); emit q->closed(); @@ -314,6 +318,18 @@ void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow) if (window == newWindow) return; + if (window) { + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + if (overlay) + QQuickOverlayPrivate::get(overlay)->removePopup(q); + } + + if (newWindow) { + QQuickOverlay *overlay = QQuickOverlay::overlay(newWindow); + if (overlay) + QQuickOverlayPrivate::get(overlay)->addPopup(q); + } + window = newWindow; emit q->windowChanged(newWindow); } @@ -711,19 +727,15 @@ bool QQuickPopupPositioner::isAncestor(QQuickItem *item) const } QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup) - : QQuickTransitionManager() - , state(Off) - , popup(popup) + : QQuickTransitionManager(), popup(popup) { } void QQuickPopupTransitionManager::transitionEnter() { - if (state == Enter && isRunning()) + if (!popup->prepareEnterTransition()) return; - state = Enter; - popup->prepareEnterTransition(); if (popup->window) transition(popup->enterActions, popup->enter, popup->q_func()); else @@ -732,11 +744,9 @@ void QQuickPopupTransitionManager::transitionEnter() void QQuickPopupTransitionManager::transitionExit() { - if (state == Exit && isRunning()) + if (!popup->prepareExitTransition()) return; - state = Exit; - popup->prepareExitTransition(); if (popup->window) transition(popup->exitActions, popup->exit, popup->q_func()); else @@ -745,12 +755,10 @@ void QQuickPopupTransitionManager::transitionExit() void QQuickPopupTransitionManager::finished() { - if (state == Enter) + if (popup->transitionState == QQuickPopupPrivate::EnterTransition) popup->finalizeEnterTransition(); - else if (state == Exit) + else if (popup->transitionState == QQuickPopupPrivate::ExitTransition) popup->finalizeExitTransition(); - - state = Off; } QQuickPopup::QQuickPopup(QObject *parent) @@ -1895,13 +1903,6 @@ bool QQuickPopup::isComponentComplete() const return d->complete; } -bool QQuickPopup::eventFilter(QObject *object, QEvent *event) -{ - if (QQuickWindow *window = qobject_cast<QQuickWindow *>(object)) - return overlayEvent(window->contentItem(), event); - return false; -} - bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event) { Q_UNUSED(child); @@ -1961,6 +1962,12 @@ void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event) void QQuickPopup::mouseUngrabEvent() { + QQuickOverlay *overlay = QQuickOverlay::overlay(window()); + if (overlay) { + QQuickOverlayPrivate *p = QQuickOverlayPrivate::get(overlay); + if (p->mouseGrabberPopup == this) + p->mouseGrabberPopup = nullptr; + } } bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event) diff --git a/src/quicktemplates2/qquickpopup_p.h b/src/quicktemplates2/qquickpopup_p.h index 1f2cabcf..5f5fd6bd 100644 --- a/src/quicktemplates2/qquickpopup_p.h +++ b/src/quicktemplates2/qquickpopup_p.h @@ -344,7 +344,6 @@ protected: void componentComplete() override; bool isComponentComplete() const; - bool eventFilter(QObject *object, QEvent *event) override; virtual bool childMouseEventFilter(QQuickItem *child, QEvent *event); virtual void focusInEvent(QFocusEvent *event); virtual void focusOutEvent(QFocusEvent *event); diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h index 4478c555..93039287 100644 --- a/src/quicktemplates2/qquickpopup_p_p.h +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -76,11 +76,6 @@ protected: void finished() override; private: - enum TransitionState { - Off, Enter, Exit - }; - - TransitionState state; QQuickPopupPrivate *popup; }; @@ -163,10 +158,10 @@ public: bool tryClose(QQuickItem *item, QMouseEvent *event); virtual void reposition(); - virtual void prepareEnterTransition(bool notify = true); - virtual void prepareExitTransition(); + virtual bool prepareEnterTransition(); + virtual bool prepareExitTransition(); virtual void finalizeEnterTransition(); - virtual void finalizeExitTransition(bool hide = true); + virtual void finalizeExitTransition(); QMarginsF getMargins() const; @@ -178,6 +173,10 @@ public: void setWindow(QQuickWindow *window); void itemDestroyed(QQuickItem *item) override; + enum TransitionState { + NoTransition, EnterTransition, ExitTransition + }; + bool focus; bool modal; bool dim; @@ -202,6 +201,7 @@ public: qreal bottomMargin; qreal contentWidth; qreal contentHeight; + TransitionState transitionState; QQuickPopup::ClosePolicy closePolicy; QQuickItem *parentItem; QQuickItem *dimmer; diff --git a/src/quicktemplates2/qquickroundbutton.cpp b/src/quicktemplates2/qquickroundbutton.cpp new file mode 100644 index 00000000..4169b269 --- /dev/null +++ b/src/quicktemplates2/qquickroundbutton.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickroundbutton_p.h" + +#include <QtQuickTemplates2/private/qquickbutton_p_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype RoundButton + \inherits Button + \instantiates QQuickRoundButton + \inqmlmodule QtQuick.Controls + \since 5.8 + \ingroup qtquickcontrols2-buttons + \brief A push-button control with rounded corners that can be clicked by the user. + + \image qtquickcontrols2-roundbutton.png + + RoundButton is identical to \l Button, except that it has a \l radius property + which allows the corners to be rounded without having to customize the + \l background. + + \snippet qtquickcontrols2-roundbutton.qml 1 + + \sa {Customizing RoundButton}, {Button Controls} +*/ + +class QQuickRoundButtonPrivate : public QQuickButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickRoundButton) + +public: + QQuickRoundButtonPrivate(); + + qreal radius; + bool explicitRadius; + + void setRadius(qreal newRadius = -1.0); +}; + +QQuickRoundButtonPrivate::QQuickRoundButtonPrivate() : + radius(0), + explicitRadius(false) +{ +} + +void QQuickRoundButtonPrivate::setRadius(qreal newRadius) +{ + Q_Q(QQuickRoundButton); + const qreal oldRadius = radius; + if (newRadius < 0) + radius = qMax<qreal>(0, qMin(width, height) / 2); + else + radius = newRadius; + + if (!qFuzzyCompare(radius, oldRadius)) + emit q->radiusChanged(); +} + +QQuickRoundButton::QQuickRoundButton(QQuickItem *parent) : + QQuickButton(*(new QQuickRoundButtonPrivate), parent) +{ +} + +/*! + \qmlproperty real QtQuick.Controls::RoundButton::radius + + This property holds the radius of the button. + + To create a relatively square button that has slightly rounded corners, + use a small value, such as \c 3. + + To create a completely circular button (the default), use a value that is + equal to half of the width or height of the button, and make the button's + width and height identical. + + To reset this property back to the default value, set its value to + \c undefined. +*/ +qreal QQuickRoundButton::radius() const +{ + Q_D(const QQuickRoundButton); + return d->radius; +} + +void QQuickRoundButton::setRadius(qreal radius) +{ + Q_D(QQuickRoundButton); + d->explicitRadius = true; + d->setRadius(radius); +} + +void QQuickRoundButton::resetRadius() +{ + Q_D(QQuickRoundButton); + d->explicitRadius = false; + d->setRadius(); +} + +void QQuickRoundButton::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickRoundButton); + QQuickControl::geometryChanged(newGeometry, oldGeometry); + if (!d->explicitRadius) + d->setRadius(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickroundbutton_p.h b/src/quicktemplates2/qquickroundbutton_p.h new file mode 100644 index 00000000..f308ddd3 --- /dev/null +++ b/src/quicktemplates2/qquickroundbutton_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKROUNDBUTTON_P_H +#define QQUICKROUNDBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtQuickTemplates2/private/qquickbutton_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickRoundButtonPrivate; + +class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRoundButton : public QQuickButton +{ + Q_OBJECT + Q_PROPERTY(qreal radius READ radius WRITE setRadius RESET resetRadius NOTIFY radiusChanged FINAL) + +public: + explicit QQuickRoundButton(QQuickItem *parent = nullptr); + + qreal radius() const; + void setRadius(qreal radius); + void resetRadius(); + +Q_SIGNALS: + void radiusChanged(); + +protected: + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + +private: + Q_DISABLE_COPY(QQuickRoundButton) + Q_DECLARE_PRIVATE(QQuickRoundButton) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickRoundButton) + +#endif // QQUICKROUNDBUTTON_P_H diff --git a/src/quicktemplates2/qquickscrollindicator.cpp b/src/quicktemplates2/qquickscrollindicator.cpp index acb8dd46..351f3113 100644 --- a/src/quicktemplates2/qquickscrollindicator.cpp +++ b/src/quicktemplates2/qquickscrollindicator.cpp @@ -109,12 +109,17 @@ void QQuickScrollIndicatorPrivate::resizeContent() if (!contentItem) return; + // - negative overshoot (pos < 0): clamp the pos to 0, and deduct the overshoot from the size + // - positive overshoot (pos + size > 1): clamp the size to 1-pos + const qreal clampedSize = qBound<qreal>(0, size + qMin<qreal>(0, position), 1.0 - position); + const qreal clampedPos = qBound<qreal>(0, position, 1.0 - clampedSize); + if (orientation == Qt::Horizontal) { - contentItem->setPosition(QPointF(q->leftPadding() + position * q->availableWidth(), q->topPadding())); - contentItem->setSize(QSizeF(q->availableWidth() * size, q->availableHeight())); + contentItem->setPosition(QPointF(q->leftPadding() + clampedPos * q->availableWidth(), q->topPadding())); + contentItem->setSize(QSizeF(q->availableWidth() * clampedSize, q->availableHeight())); } else { - contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + position * q->availableHeight())); - contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * size)); + contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + clampedPos * q->availableHeight())); + contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * clampedSize)); } } diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp index df163089..040eff1b 100644 --- a/src/quicktemplates2/qquickstackview.cpp +++ b/src/quicktemplates2/qquickstackview.cpp @@ -1092,4 +1092,21 @@ QQuickStackView::Status QQuickStackAttached::status() const \sa status */ +/*! + \qmlattachedsignal QtQuick.Controls::StackView::removed() + \since QtQuick.Controls 2.1 + + This attached signal is emitted when the item it's attached to has been + removed from the stack. It can be used to safely destroy an Item that was + pushed onto the stack, for example: + + \code + Item { + StackView.onRemoved: destroy() // Will be destroyed sometime after this call. + } + \endcode + + \sa status +*/ + QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickstackview_p.cpp b/src/quicktemplates2/qquickstackview_p.cpp index 0f5674c2..438b4269 100644 --- a/src/quicktemplates2/qquickstackview_p.cpp +++ b/src/quicktemplates2/qquickstackview_p.cpp @@ -85,6 +85,7 @@ QQuickStackElement::~QQuickStackElement() if (ownComponent) delete component; + QQuickStackAttached *attached = attachedStackObject(this); if (item) { if (ownItem) { item->setParentItem(nullptr); @@ -99,13 +100,15 @@ QQuickStackElement::~QQuickStackElement() if (item->parentItem() != originalParent) { item->setParentItem(originalParent); } else { - QQuickStackAttached *attached = attachedStackObject(this); if (attached) QQuickStackAttachedPrivate::get(attached)->itemParentChanged(item, nullptr); } } } + if (attached) + emit attached->removed(); + delete context; } diff --git a/src/quicktemplates2/qquickstackview_p.h b/src/quicktemplates2/qquickstackview_p.h index d8b6ce7c..9bf60183 100644 --- a/src/quicktemplates2/qquickstackview_p.h +++ b/src/quicktemplates2/qquickstackview_p.h @@ -182,6 +182,7 @@ Q_SIGNALS: /*Q_REVISION(1)*/ void activating(); /*Q_REVISION(1)*/ void deactivated(); /*Q_REVISION(1)*/ void deactivating(); + /*Q_REVISION(1)*/ void removed(); private: Q_DISABLE_COPY(QQuickStackAttached) diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index 439950d8..37ae53f0 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -37,6 +37,8 @@ #include "qquickswitch_p.h" #include "qquickabstractbutton_p_p.h" +#include <QtGui/qstylehints.h> +#include <QtGui/qguiapplication.h> #include <QtQuick/private/qquickwindow_p.h> #include <QtQuick/private/qquickevents_p_p.h> @@ -119,8 +121,12 @@ bool QQuickSwitchPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent * { 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; } @@ -140,6 +146,9 @@ bool QQuickSwitchPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent *e 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()) { @@ -147,11 +156,14 @@ bool QQuickSwitchPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent q->setChecked(position > 0.5); q->setPosition(checked ? 1.0 : 0.0); child->setKeepMouseGrab(false); - if (wasChecked != checked) + if (wasChecked != checked) { + emit q->released(); emit q->clicked(); + } event->accept(); } else { q->toggle(); + emit q->released(); emit q->clicked(); event->accept(); } diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri index f5e95aea..0d6a0e5a 100644 --- a/src/quicktemplates2/quicktemplates2.pri +++ b/src/quicktemplates2/quicktemplates2.pri @@ -6,6 +6,7 @@ HEADERS += \ $$PWD/qquickapplicationwindow_p.h \ $$PWD/qquickbusyindicator_p.h \ $$PWD/qquickbutton_p.h \ + $$PWD/qquickbutton_p_p.h \ $$PWD/qquickbuttongroup_p.h \ $$PWD/qquickcheckbox_p.h \ $$PWD/qquickcheckdelegate_p.h \ @@ -20,6 +21,7 @@ HEADERS += \ $$PWD/qquickdialogbuttonbox_p.h \ $$PWD/qquickdialogbuttonbox_p_p.h \ $$PWD/qquickdrawer_p.h \ + $$PWD/qquickdrawer_p_p.h \ $$PWD/qquickframe_p.h \ $$PWD/qquickframe_p_p.h \ $$PWD/qquickgroupbox_p.h \ @@ -32,6 +34,7 @@ HEADERS += \ $$PWD/qquickmenuitem_p.h \ $$PWD/qquickmenuseparator_p.h \ $$PWD/qquickoverlay_p.h \ + $$PWD/qquickoverlay_p_p.h \ $$PWD/qquickpage_p.h \ $$PWD/qquickpageindicator_p.h \ $$PWD/qquickpagelayout_p_p.h \ @@ -44,6 +47,7 @@ HEADERS += \ $$PWD/qquickradiobutton_p.h \ $$PWD/qquickradiodelegate_p.h \ $$PWD/qquickrangeslider_p.h \ + $$PWD/qquickroundbutton_p.h \ $$PWD/qquickscrollbar_p.h \ $$PWD/qquickscrollindicator_p.h \ $$PWD/qquickslider_p.h \ @@ -101,6 +105,7 @@ SOURCES += \ $$PWD/qquickradiobutton.cpp \ $$PWD/qquickradiodelegate.cpp \ $$PWD/qquickrangeslider.cpp \ + $$PWD/qquickroundbutton.cpp \ $$PWD/qquickscrollbar.cpp \ $$PWD/qquickscrollindicator.cpp \ $$PWD/qquickslider.cpp \ |