From ad25ebd08247579754243b09f8fa60b778d9a3aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Wed, 23 Sep 2020 13:13:02 +0200 Subject: windows: Add hover animation to Button and CheckBox Move the hover animation handling API from macOS ScrollBar down to QQuickStyleItem. Change-Id: I36c8b173a15d0f4e10a59b7f3ccfe635e05c73e7 Reviewed-by: Richard Moe Gustavsen --- src/imports/controls/macos/ScrollBar.qml | 4 +- src/imports/controls/windows/Button.qml | 12 ++++ src/imports/controls/windows/CheckBox.qml | 68 +++++++++++++++++++++- src/imports/nativestyle/items/qquickstyleitem.cpp | 9 +++ src/imports/nativestyle/items/qquickstyleitem.h | 18 ++++++ .../nativestyle/items/qquickstyleitemscrollbar.cpp | 2 - .../nativestyle/items/qquickstyleitemscrollbar.h | 17 ------ 7 files changed, 108 insertions(+), 22 deletions(-) diff --git a/src/imports/controls/macos/ScrollBar.qml b/src/imports/controls/macos/ScrollBar.qml index 94416acd..d0ad6e9b 100644 --- a/src/imports/controls/macos/ScrollBar.qml +++ b/src/imports/controls/macos/ScrollBar.qml @@ -55,10 +55,10 @@ NativeStyle.DefaultScrollBar { height: contentItem.height control: controlRoot subControl: NativeStyle.ScrollBar.Handle - overrideState: NativeStyle.ScrollBar.AlwaysHovered + overrideState: NativeStyle.StyleItem.AlwaysHovered opacity: controlRoot.hovered || control.pressed ? 1 : 0 visible: contentItem instanceof NativeStyle.StyleItem - Behavior on opacity { NumberAnimation { duration: 150 } } + Behavior on opacity { NumberAnimation { duration: parent.transitionDuration } } } } diff --git a/src/imports/controls/windows/Button.qml b/src/imports/controls/windows/Button.qml index 751cfb3f..99b909f8 100644 --- a/src/imports/controls/windows/Button.qml +++ b/src/imports/controls/windows/Button.qml @@ -62,7 +62,19 @@ T.Button { contentWidth: contentItem.implicitWidth contentHeight: contentItem.implicitHeight useNinePatchImage: false + overrideState: NativeStyle.StyleItem.NeverHovered + } + NativeStyle.Button { + control: control + x: background.x + y: background.y + width: background.width + height: background.height + useNinePatchImage: false + overrideState: NativeStyle.StyleItem.AlwaysHovered + opacity: control.hovered ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: parent.transitionDuration } } } icon.width: 24 diff --git a/src/imports/controls/windows/CheckBox.qml b/src/imports/controls/windows/CheckBox.qml index d1a56fee..03778c4f 100644 --- a/src/imports/controls/windows/CheckBox.qml +++ b/src/imports/controls/windows/CheckBox.qml @@ -35,7 +35,73 @@ ****************************************************************************/ import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls +import QtQuick.Controls.impl import QtQuick.NativeStyle as NativeStyle -NativeStyle.DefaultCheckBox { +T.CheckBox { + id: control + + readonly property bool nativeIndicator: indicator instanceof NativeStyle.StyleItem + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + font.pixelSize: nativeIndicator ? indicator.styleFont(control).pixelSize : undefined + + spacing: nativeIndicator ? 0 : 6 + padding: nativeIndicator ? 0 : 6 + + indicator: NativeStyle.CheckBox { + control: control + y: control.topPadding + (control.availableHeight - height) >> 1 + contentWidth: contentItem.implicitWidth + contentHeight: contentItem.implicitHeight + useNinePatchImage: false + overrideState: NativeStyle.StyleItem.NeverHovered + } + + NativeStyle.CheckBox { + control: control + x: indicator.x + y: indicator.y + z: 99 // Needs to be above the "unhovered" indicator + width: indicator.width + height: indicator.height + useNinePatchImage: false + overrideState: NativeStyle.StyleItem.AlwaysHovered + opacity: control.hovered ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: parent.transitionDuration } } + } + + contentItem: CheckLabel { + text: control.text + font: control.font + color: control.palette.windowText + + // For some reason, the other styles set padding here (in the delegate), instead of in + // the control above. And they also adjust the indicator position by setting x and y + // explicitly (instead of using insets). So we follow the same pattern to ensure that + // setting a custom contentItem delegate from the app will end up looking the same for + // all styles. But this should probably be fixed for all styles (to make them work the + // same way as e.g Buttons). + leftPadding: { + if (nativeIndicator) + indicator.contentPadding.left + else + indicator && !mirrored ? indicator.width + spacing : 0 + } + + topPadding: nativeIndicator ? indicator.contentPadding.top : 0 + rightPadding: { + if (nativeIndicator) + indicator.contentPadding.right + else + indicator && mirrored ? indicator.width + spacing : 0 + } + } } diff --git a/src/imports/nativestyle/items/qquickstyleitem.cpp b/src/imports/nativestyle/items/qquickstyleitem.cpp index 03659aa2..c45f0c91 100644 --- a/src/imports/nativestyle/items/qquickstyleitem.cpp +++ b/src/imports/nativestyle/items/qquickstyleitem.cpp @@ -196,6 +196,15 @@ void QQuickStyleItem::initStyleOptionBase(QStyleOption &styleOption) styleOption.state |= QStyle::State_KeyboardFocusChange; } + if (m_overrideState != None) { + // In Button.qml we fade between two versions of + // the handle, depending on if it's hovered or not + if (m_overrideState & AlwaysHovered) + styleOption.state |= QStyle::State_MouseOver; + else if (m_overrideState & NeverHovered) + styleOption.state &= ~QStyle::State_MouseOver; + } + qqc2Debug() << styleOption; } diff --git a/src/imports/nativestyle/items/qquickstyleitem.h b/src/imports/nativestyle/items/qquickstyleitem.h index 3d5bfc31..ff870684 100644 --- a/src/imports/nativestyle/items/qquickstyleitem.h +++ b/src/imports/nativestyle/items/qquickstyleitem.h @@ -160,6 +160,9 @@ class QQuickStyleItem : public QQuickItem Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight) Q_PROPERTY(bool useNinePatchImage MEMBER m_useNinePatchImage) + Q_PROPERTY(OverrideState overrideState MEMBER m_overrideState) + Q_PROPERTY(int transitionDuration MEMBER m_transitionDuration) + // Output Q_PROPERTY(QQuickStyleMargins contentPadding READ contentPadding() NOTIFY contentPaddingChanged) Q_PROPERTY(QQuickStyleMargins layoutMargins READ layoutMargins() NOTIFY layoutMarginsChanged) @@ -176,6 +179,14 @@ public: }; Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag) + enum OverrideState { + None = 0, + AlwaysHovered, + NeverHovered, + }; + Q_ENUM(OverrideState) + + #ifdef QT_DEBUG enum DebugFlag { NoDebug = 0x00, @@ -244,6 +255,7 @@ protected: #ifdef QT_DEBUG DebugFlags m_debugFlags = NoDebug; #endif + OverrideState m_overrideState = None; private: inline void updateGeometry(); @@ -259,6 +271,12 @@ private: bool m_useNinePatchImage = true; bool m_polishing = false; +#ifdef Q_OS_MACOS + int m_transitionDuration = 150; +#else + int m_transitionDuration = 400; +#endif + private: friend class QtQuickControls2MacOSStylePlugin; }; diff --git a/src/imports/nativestyle/items/qquickstyleitemscrollbar.cpp b/src/imports/nativestyle/items/qquickstyleitemscrollbar.cpp index 72f850a8..77185b48 100644 --- a/src/imports/nativestyle/items/qquickstyleitemscrollbar.cpp +++ b/src/imports/nativestyle/items/qquickstyleitemscrollbar.cpp @@ -83,7 +83,6 @@ void QQuickStyleItemScrollBar::initStyleOption(QStyleOptionSlider &styleOption) if (scrollBar->isPressed()) styleOption.state |= QStyle::State_Sunken; -#ifdef Q_OS_MACOS if (m_overrideState != None) { // In ScrollBar.qml we fade between two versions of // the handle, depending on if it's hovered or not @@ -92,7 +91,6 @@ void QQuickStyleItemScrollBar::initStyleOption(QStyleOptionSlider &styleOption) else if (m_overrideState & NeverHovered) styleOption.state &= ~QStyle::State_Sunken; } -#endif // The following values will let the handle fill 100% of the // groove / imageSize. But when the handle is resized by diff --git a/src/imports/nativestyle/items/qquickstyleitemscrollbar.h b/src/imports/nativestyle/items/qquickstyleitemscrollbar.h index db241ad8..e181d4ec 100644 --- a/src/imports/nativestyle/items/qquickstyleitemscrollbar.h +++ b/src/imports/nativestyle/items/qquickstyleitemscrollbar.h @@ -46,10 +46,6 @@ class QQuickStyleItemScrollBar : public QQuickStyleItem Q_PROPERTY(SubControl subControl MEMBER m_subControl) -#ifdef Q_OS_MACOS - Q_PROPERTY(OverrideState overrideState MEMBER m_overrideState) -#endif - QML_NAMED_ELEMENT(ScrollBar) public: @@ -59,15 +55,6 @@ public: }; Q_ENUM(SubControl) -#ifdef Q_OS_MACOS - enum OverrideState { - None = 0, - AlwaysHovered, - NeverHovered, - }; - Q_ENUM(OverrideState) -#endif - QFont styleFont(QQuickItem *control) override; protected: @@ -80,10 +67,6 @@ private: private: SubControl m_subControl = Groove; - -#ifdef Q_OS_MACOS - OverrideState m_overrideState = None; -#endif }; #endif // QQUICKSTYLEITEMSCROLLBAR_H -- cgit v1.2.3