diff options
Diffstat (limited to 'src/quickcontrols/windows')
28 files changed, 816 insertions, 10 deletions
diff --git a/src/quickcontrols/windows/ApplicationWindow.qml b/src/quickcontrols/windows/ApplicationWindow.qml new file mode 100644 index 0000000000..dc3094c009 --- /dev/null +++ b/src/quickcontrols/windows/ApplicationWindow.qml @@ -0,0 +1,9 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick.NativeStyle +import QtQuick.Templates as T + +T.ApplicationWindow { + color: palette.window +} diff --git a/src/quickcontrols/windows/CMakeLists.txt b/src/quickcontrols/windows/CMakeLists.txt index b5319fef52..36e871abdb 100644 --- a/src/quickcontrols/windows/CMakeLists.txt +++ b/src/quickcontrols/windows/CMakeLists.txt @@ -6,16 +6,30 @@ ##################################################################### set(qml_files + "ApplicationWindow.qml" "Button.qml" "CheckBox.qml" + "CheckDelegate.qml" "ComboBox.qml" + "DelayButton.qml" "Frame.qml" "GroupBox.qml" + "ItemDelegate.qml" + "Menu.qml" + "MenuBar.qml" + "MenuBarItem.qml" + "MenuItem.qml" + "MenuSeparator.qml" "ProgressBar.qml" "RadioButton.qml" + "RadioDelegate.qml" + "RangeSlider.qml" + "ScrollIndicator.qml" "SelectionRectangle.qml" "Slider.qml" "SpinBox.qml" + "Switch.qml" + "SwitchDelegate.qml" "TextArea.qml" "TextField.qml" "ScrollBar.qml" @@ -36,6 +50,13 @@ qt_internal_add_qml_module(qtquickcontrols2windowsstyleplugin qtquickcontrols2windowsstyleplugin.cpp QML_FILES ${qml_files} + RESOURCES + images/checkmark.png + images/checkmark@2x.png + images/checkmark@3x.png + images/menuarrow.png + images/menuarrow@2x.png + images/menuarrow@3x.png DEFINES QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII @@ -44,10 +65,13 @@ qt_internal_add_qml_module(qtquickcontrols2windowsstyleplugin Qt::GuiPrivate Qt::QmlPrivate Qt::QuickControls2Private + Qt::QuickControls2WindowsStyleImpl Qt::QuickPrivate Qt::QuickTemplates2Private ) +add_subdirectory(impl) + # Native style is a dependency of the Windows style. _qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2windowsstyleplugin qtquickcontrols2nativestyleplugin) diff --git a/src/quickcontrols/windows/CheckDelegate.qml b/src/quickcontrols/windows/CheckDelegate.qml new file mode 100644 index 0000000000..ce020161c8 --- /dev/null +++ b/src/quickcontrols/windows/CheckDelegate.qml @@ -0,0 +1,75 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls +import QtQuick.Controls.impl +import QtQuick.NativeStyle as NativeStyle + +T.CheckDelegate { + id: control + + readonly property bool __nativeIndicator: indicator instanceof NativeStyle.StyleItem + readonly property bool __notCustomizable: true + readonly property Item __focusFrameTarget: indicator + readonly property Item __focusFrameStyleItem: indicator + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + spacing: 6 + padding: 6 + + contentItem: NativeStyle.DefaultItemDelegateIconLabel { + color: control.highlighted ? control.palette.button : control.palette.windowText + + readonly property bool __ignoreNotCustomizable: true + } + + indicator: NativeStyle.CheckDelegate { + x: control.text + ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) + : control.leftPadding + (control.availableWidth - width) / 2 + // The rendering gets messed up when rendering on sub-pixel positions. + y: control.topPadding + Math.round((control.availableHeight - height) / 2) + contentWidth: control.implicitContentWidth + contentHeight: control.implicitContentHeight + control: control + useNinePatchImage: false + overrideState: NativeStyle.StyleItem.NeverHovered + + readonly property bool __ignoreNotCustomizable: true + } + + NativeStyle.CheckDelegate { + id: hoverCheckDelegate + control: control + x: control.indicator.x + y: control.indicator.y + z: control.indicator.z + 1 + width: control.indicator.width + height: control.indicator.height + useNinePatchImage: false + overrideState: NativeStyle.StyleItem.AlwaysHovered + opacity: control.hovered ? 1 : 0 + visible: opacity !== 0 + Behavior on opacity { + NumberAnimation { + duration: hoverCheckDelegate.transitionDuration + } + } + } + + background: Rectangle { + implicitWidth: 100 + implicitHeight: 20 + color: Qt.darker(control.highlighted + ? control.palette.highlight : control.palette.button, control.down ? 1.05 : 1) + + readonly property bool __ignoreNotCustomizable: true + } +} diff --git a/src/quickcontrols/windows/ComboBox.qml b/src/quickcontrols/windows/ComboBox.qml index 66fffecb46..e8a0ed738d 100644 --- a/src/quickcontrols/windows/ComboBox.qml +++ b/src/quickcontrols/windows/ComboBox.qml @@ -1,6 +1,8 @@ // Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Window import QtQuick.Controls @@ -56,8 +58,11 @@ T.ComboBox { } delegate: ItemDelegate { + required property var model + required property int index + width: ListView.view.width - text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData + text: model[control.textRole] palette.text: control.palette.text palette.highlightedText: control.palette.highlightedText font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal diff --git a/src/quickcontrols/windows/DelayButton.qml b/src/quickcontrols/windows/DelayButton.qml new file mode 100644 index 0000000000..935e5cc86a --- /dev/null +++ b/src/quickcontrols/windows/DelayButton.qml @@ -0,0 +1,82 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Controls.impl +import QtQuick.Templates as T +import QtQuick.NativeStyle as NativeStyle + +T.DelayButton { + id: control + + readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem + readonly property bool __notCustomizable: true + readonly property Item __focusFrameTarget: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + leftPadding: __nativeBackground ? background.contentPadding.left : 5 + rightPadding: __nativeBackground ? background.contentPadding.right : 5 + topPadding: __nativeBackground ? background.contentPadding.top : 5 + bottomPadding: __nativeBackground ? background.contentPadding.bottom : 5 + + icon.width: 24 + icon.height: 24 + icon.color: control.palette.buttonText + + transition: Transition { + NumberAnimation { + duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress) + } + } + + background: NativeStyle.DelayButton { + control: control + contentWidth: contentItem.implicitWidth + contentHeight: contentItem.implicitHeight + useNinePatchImage: false + overrideState: NativeStyle.StyleItem.NeverHovered + + readonly property bool __ignoreNotCustomizable: true + } + + NativeStyle.DelayButton { + id: hoverButton + 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 + visible: opacity !== 0 + Behavior on opacity { NumberAnimation { duration: hoverButton.transitionDuration } } + } + + contentItem: IconLabel { + spacing: control.spacing + mirrored: control.mirrored + display: control.display + + icon: control.icon + text: control.text + font: control.font + color: control.palette.buttonText + + readonly property bool __ignoreNotCustomizable: true + + // Delay progress bar. + Rectangle { + x: (parent.width - parent.implicitWidth) / 2 + y: parent.height + 1 + width: control.progress * parent.implicitWidth + height: 1 + color: control.palette.accent + scale: control.mirrored ? -1 : 1 + } + } +} diff --git a/src/quickcontrols/windows/ItemDelegate.qml b/src/quickcontrols/windows/ItemDelegate.qml new file mode 100644 index 0000000000..879c4532ec --- /dev/null +++ b/src/quickcontrols/windows/ItemDelegate.qml @@ -0,0 +1,10 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick.NativeStyle as NativeStyle + +NativeStyle.DefaultItemDelegate { + contentItem: NativeStyle.DefaultItemDelegateIconLabel { + color: control.highlighted ? control.palette.button : control.palette.windowText + } +} diff --git a/src/quickcontrols/windows/Menu.qml b/src/quickcontrols/windows/Menu.qml new file mode 100644 index 0000000000..0b110d7744 --- /dev/null +++ b/src/quickcontrols/windows/Menu.qml @@ -0,0 +1,74 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls.impl +import QtQuick.Window +import QtQuick.Effects + +T.Menu { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + contentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + contentHeight + topPadding + bottomPadding) + + // The insets are found by examining the MultiEffect.itemRect, which + // contains the drop shadow offsets. QQuickPopup will subract these insets when + // it opens up the menu so that the top left corner of the background ends up at + // the requested popup position. + // Note: the insets are hard-coded to avoid a binding loop to implicit size. + leftInset: 32 + topInset: 32 + rightInset: 32 + bottomInset: 32 + leftPadding: leftInset + 5 + rightPadding: rightInset + 5 + topPadding: topInset + 5 + bottomPadding: bottomInset + 5 + margins: 0 + overlap: 4 + + delegate: MenuItem { } + + contentItem: ListView { + implicitHeight: contentHeight + model: control.contentModel + interactive: Window.window + ? contentHeight + control.topPadding + control.bottomPadding > control.height + : false + currentIndex: control.currentIndex + spacing: 2 + + ScrollIndicator.vertical: ScrollIndicator {} + } + + background: MultiEffect { + implicitWidth: 200 + implicitHeight: 20 + source: Rectangle { + width: control.background.width + height: control.background.height + radius: 8 + color: Qt.lighter(control.palette.window, 1.15) + border.color: Qt.darker(control.palette.window, 1.12) + visible: false + } + shadowScale: 1.04 + shadowOpacity: 0.1 + shadowColor: 'black' + shadowEnabled: true + shadowHorizontalOffset: 0 + shadowVerticalOffset: 10 + } + + T.Overlay.modal: Rectangle { + color: "transparent" + } + + T.Overlay.modeless: Rectangle { + color: "transparent" + } +} diff --git a/src/quickcontrols/windows/MenuBar.qml b/src/quickcontrols/windows/MenuBar.qml new file mode 100644 index 0000000000..ec998abde7 --- /dev/null +++ b/src/quickcontrols/windows/MenuBar.qml @@ -0,0 +1,35 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls.impl + +T.MenuBar { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + contentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + contentHeight + topPadding + bottomPadding) + + leftPadding: 3 + rightPadding: 3 + topPadding: 3 + bottomPadding: 3 + spacing: 10 + + delegate: MenuBarItem { } + + contentItem: Row { + spacing: control.spacing + Repeater { + model: control.contentModel + } + } + + background: Rectangle { + implicitHeight: 20 + color: "white" // window title bar color + } +} diff --git a/src/quickcontrols/windows/MenuBarItem.qml b/src/quickcontrols/windows/MenuBarItem.qml new file mode 100644 index 0000000000..fe71542153 --- /dev/null +++ b/src/quickcontrols/windows/MenuBarItem.qml @@ -0,0 +1,47 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls.impl + +T.MenuBarItem { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + topPadding: 8 + bottomPadding: 8 + leftPadding: 10 + rightPadding: 10 + spacing: 6 + + icon.width: 16 + icon.height: 16 + + contentItem: IconLabel { + spacing: control.spacing + mirrored: control.mirrored + display: control.display + alignment: Qt.AlignLeft + + icon: control.icon + text: control.text + font: control.font + color: control.palette.text + } + + background: Rectangle { + implicitWidth: 20 + implicitHeight: 20 + + color: "black" + opacity: 0.05 + radius: 4 + visible: control.down || control.highlighted + } +} diff --git a/src/quickcontrols/windows/MenuItem.qml b/src/quickcontrols/windows/MenuItem.qml new file mode 100644 index 0000000000..0d3c4f89f6 --- /dev/null +++ b/src/quickcontrols/windows/MenuItem.qml @@ -0,0 +1,74 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls.impl +import QtQuick.Controls.Windows.impl + +T.MenuItem { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + leftPadding: 10 + rightPadding: 10 + topPadding: 3 + bottomPadding: 3 + spacing: 6 + + icon.width: 16 + icon.height: 16 + + implicitTextPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0 + + contentItem: IconLabel { + readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0 + leftPadding: !control.mirrored ? control.textPadding : arrowPadding + rightPadding: control.mirrored ? control.textPadding : arrowPadding + + spacing: control.spacing + mirrored: control.mirrored + display: control.display + alignment: Qt.AlignLeft + + icon: control.icon + text: control.text + font: control.font + color: control.palette.text + } + + arrow: ColorImage { + x: control.mirrored ? control.padding : control.width - width - control.padding + y: control.topPadding + (control.availableHeight - height) / 2 + width: 20 + + visible: control.subMenu + rotation: control.mirrored ? -180 : 0 + color: control.palette.text + source: "qrc:/qt-project.org/imports/QtQuick/Controls/Windows/images/menuarrow.png" + fillMode: Image.Pad + } + + indicator: CheckIndicator { + x: control.mirrored ? control.width - width - control.rightPadding : control.leftPadding + y: control.topPadding + (control.availableHeight - height) / 2 + + control: control + visible: control.checkable + } + + background: Rectangle { + implicitWidth: 200 + implicitHeight: 30 + radius: 4 + + color: control.palette.dark + opacity: 0.1 + visible: control.down || control.highlighted + } +} diff --git a/src/quickcontrols/windows/MenuSeparator.qml b/src/quickcontrols/windows/MenuSeparator.qml new file mode 100644 index 0000000000..6559be9958 --- /dev/null +++ b/src/quickcontrols/windows/MenuSeparator.qml @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T + +T.MenuSeparator { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + horizontalPadding: 0 + verticalPadding: 2 + + contentItem: Rectangle { + implicitWidth: 188 + implicitHeight: 1 + color: control.palette.midlight + } +} diff --git a/src/quickcontrols/windows/RadioDelegate.qml b/src/quickcontrols/windows/RadioDelegate.qml new file mode 100644 index 0000000000..e74e42350b --- /dev/null +++ b/src/quickcontrols/windows/RadioDelegate.qml @@ -0,0 +1,12 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick.NativeStyle as NativeStyle + +NativeStyle.DefaultRadioDelegate { + contentItem: NativeStyle.DefaultItemDelegateIconLabel { + color: control.highlighted ? control.palette.button : control.palette.windowText + + readonly property bool __ignoreNotCustomizable: true + } +} diff --git a/src/quickcontrols/windows/RangeSlider.qml b/src/quickcontrols/windows/RangeSlider.qml new file mode 100644 index 0000000000..a124163e7b --- /dev/null +++ b/src/quickcontrols/windows/RangeSlider.qml @@ -0,0 +1,105 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Templates as T + +T.RangeSlider { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + Math.max(first.implicitHandleWidth, second.implicitHandleWidth) + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + Math.max(first.implicitHandleHeight, second.implicitHandleHeight) + topPadding + bottomPadding) + + readonly property bool __notCustomizable: true + readonly property Item __focusFrameTarget: control + + component SliderHandle: Rectangle { + implicitWidth: control.horizontal ? 11 : 21 + implicitHeight: control.horizontal ? 21 : 11 + color: control.palette.highlight + + required property bool pressed + } + + first.handle: SliderHandle { + x: control.leftPadding + Math.round(control.horizontal + ? control.first.visualPosition * (control.availableWidth - width) + : (control.availableWidth - width) / 2) + y: control.topPadding + Math.round(control.horizontal + ? (control.availableHeight - height) / 2 + : control.first.visualPosition * (control.availableHeight - height)) + palette: control.palette + pressed: control.first.pressed + + // We are the ones that get focus, but we want the control to + // be used for the visual focus frame. + readonly property Item __focusFrameControl: control + readonly property bool __ignoreNotCustomizable: true + } + + second.handle: SliderHandle { + x: control.leftPadding + Math.round(control.horizontal + ? control.second.visualPosition * (control.availableWidth - width) + : (control.availableWidth - width) / 2) + y: control.topPadding + Math.round(control.horizontal + ? (control.availableHeight - height) / 2 + : control.second.visualPosition * (control.availableHeight - height)) + palette: control.palette + pressed: control.second.pressed + + readonly property Item __focusFrameControl: control + readonly property bool __ignoreNotCustomizable: true + } + + background: Item { + implicitWidth: control.horizontal ? 90 : 21 + implicitHeight: control.horizontal ? 21 : 90 + + readonly property real __focusFrameRadius: 1 + readonly property bool __ignoreNotCustomizable: true + readonly property int barThickness: 4 + + // Groove background. + Rectangle { + x: control.leftPadding + (control.horizontal ? 0 : (control.availableWidth - width) / 2) + y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0) + width: control.horizontal ? control.availableWidth : parent.barThickness + height: control.horizontal ? parent.barThickness : control.availableHeight + color: control.palette.window + + Rectangle { + width: parent.width + height: parent.height + radius: parent.radius + // No border in dark mode, instead we fill. + color: Qt.styleHints.colorScheme === Qt.Light + ? "transparent" : Qt.lighter(control.palette.window, 1.6) + border.color: Qt.styleHints.colorScheme === Qt.Light + ? Qt.darker(control.palette.window, 1.1) + : "transparent" + } + } + + // Progress bar. + Rectangle { + x: control.leftPadding + (control.horizontal + ? control.first.position * control.availableWidth + : (control.availableWidth - width) / 2) + y: control.topPadding + (control.horizontal + ? (control.availableHeight - height) / 2 + : control.second.visualPosition * control.availableHeight) + + width: control.horizontal + ? control.second.position * control.availableWidth - control.first.position * control.availableWidth + : parent.barThickness + height: control.horizontal + ? parent.barThickness + : control.second.position * control.availableHeight - control.first.position * control.availableHeight + color: Qt.rgba(control.palette.highlight.r, control.palette.highlight.g, control.palette.highlight.b, 0.3) + } + } +} diff --git a/src/quickcontrols/windows/ScrollBar.qml b/src/quickcontrols/windows/ScrollBar.qml index 6906f7dfa2..80fbf74e75 100644 --- a/src/quickcontrols/windows/ScrollBar.qml +++ b/src/quickcontrols/windows/ScrollBar.qml @@ -7,6 +7,8 @@ import QtQuick.NativeStyle as NativeStyle NativeStyle.DefaultScrollBar { id: controlRoot + readonly property bool __notCustomizable: true + topPadding: orientation === Qt.Vertical ? controlRoot.__decreaseVisual.indicator.height : 0 bottomPadding: orientation === Qt.Vertical ? controlRoot.__increaseVisual.indicator.height : 0 leftPadding: orientation === Qt.Horizontal ? controlRoot.__decreaseVisual.indicator.width : 0 @@ -15,6 +17,8 @@ NativeStyle.DefaultScrollBar { contentItem: NativeStyle.ScrollBar { control: controlRoot subControl: NativeStyle.ScrollBar.Handle + + readonly property bool __ignoreNotCustomizable: true } NativeStyle.ScrollBar { @@ -29,7 +33,6 @@ NativeStyle.DefaultScrollBar { subControl: NativeStyle.ScrollBar.Handle overrideState: NativeStyle.StyleItem.AlwaysHovered opacity: controlRoot.hovered || control.pressed ? 1 : 0 - visible: contentItem instanceof NativeStyle.StyleItem Behavior on opacity { NumberAnimation { duration: contentItem.transitionDuration } } } @@ -47,6 +50,8 @@ NativeStyle.DefaultScrollBar { control: controlRoot subControl: NativeStyle.ScrollBar.Groove overrideState: NativeStyle.ScrollBar.NeverHovered + + readonly property bool __ignoreNotCustomizable: true } __decreaseVisual.indicator: NativeStyle.ScrollBar { @@ -54,9 +59,10 @@ NativeStyle.DefaultScrollBar { subControl: NativeStyle.ScrollBar.SubLine overrideState: NativeStyle.ScrollBar.AlwaysHovered opacity: controlRoot.__decreaseVisual.hovered ? 1 : 0 - visible: contentItem instanceof NativeStyle.StyleItem Behavior on opacity { NumberAnimation { duration: contentItem.transitionDuration } } useNinePatchImage: false + + readonly property bool __ignoreNotCustomizable: true } NativeStyle.ScrollBar { @@ -64,7 +70,6 @@ NativeStyle.DefaultScrollBar { subControl: NativeStyle.ScrollBar.SubLine overrideState: NativeStyle.ScrollBar.AlwaysSunken opacity: controlRoot.__decreaseVisual.pressed ? 1 : 0 - visible: contentItem instanceof NativeStyle.StyleItem useNinePatchImage: false z: 1 } @@ -76,9 +81,10 @@ NativeStyle.DefaultScrollBar { y: orientation === Qt.Vertical ? controlRoot.height - height : 0 overrideState: NativeStyle.ScrollBar.AlwaysHovered opacity: controlRoot.__increaseVisual.hovered ? 1 : 0 - visible: contentItem instanceof NativeStyle.StyleItem Behavior on opacity { NumberAnimation { duration: contentItem.transitionDuration } } useNinePatchImage: false + + readonly property bool __ignoreNotCustomizable: true } NativeStyle.ScrollBar { @@ -89,7 +95,6 @@ NativeStyle.DefaultScrollBar { z: 1 overrideState: NativeStyle.ScrollBar.AlwaysSunken opacity: controlRoot.__increaseVisual.pressed ? 1 : 0 - visible: contentItem instanceof NativeStyle.StyleItem useNinePatchImage: false } } diff --git a/src/quickcontrols/windows/ScrollIndicator.qml b/src/quickcontrols/windows/ScrollIndicator.qml new file mode 100644 index 0000000000..f8358eb1bf --- /dev/null +++ b/src/quickcontrols/windows/ScrollIndicator.qml @@ -0,0 +1,42 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls.impl + +T.ScrollIndicator { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + padding: 2 + + contentItem: Rectangle { + implicitWidth: 2 + implicitHeight: 2 + + color: control.palette.mid + visible: control.size < 1.0 + opacity: 0.0 + + states: State { + name: "active" + when: control.active + PropertyChanges { control.contentItem.opacity: 0.75 } + } + + transitions: [ + Transition { + from: "active" + SequentialAnimation { + PauseAnimation { duration: 450 } + NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 } + } + } + ] + } +} diff --git a/src/quickcontrols/windows/ScrollView.qml b/src/quickcontrols/windows/ScrollView.qml index 28f2d8e0fc..65d65899ca 100644 --- a/src/quickcontrols/windows/ScrollView.qml +++ b/src/quickcontrols/windows/ScrollView.qml @@ -13,8 +13,8 @@ T.ScrollView { implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, contentHeight + topPadding + bottomPadding) - rightPadding: ScrollBar.vertical.visible ? ScrollBar.vertical.width : 0 - bottomPadding: ScrollBar.horizontal.visible ? ScrollBar.horizontal.height : 0 + rightPadding: effectiveScrollBarWidth + bottomPadding: effectiveScrollBarHeight // Don't set __notCustomizable here, because it would require special-casing // setFlickable's call to setContentItem. diff --git a/src/quickcontrols/windows/SpinBox.qml b/src/quickcontrols/windows/SpinBox.qml index 982a5868a3..dcf75c0b0d 100644 --- a/src/quickcontrols/windows/SpinBox.qml +++ b/src/quickcontrols/windows/SpinBox.qml @@ -70,7 +70,7 @@ T.SpinBox { } up.indicator: Item { - x: parent.width - width - 2 + x: control.width - width - 2 y: 1 height: upAndDown.height >> 1 implicitWidth: upAndDown.implicitWidth @@ -80,7 +80,7 @@ T.SpinBox { } down.indicator: Item { - x: parent.width - width - 2 + x: control.width - width - 2 y: up.indicator.y + (upAndDown.height >> 1) height: upAndDown.height - up.indicator.height implicitWidth: upAndDown.implicitWidth diff --git a/src/quickcontrols/windows/Switch.qml b/src/quickcontrols/windows/Switch.qml new file mode 100644 index 0000000000..4e8fc48396 --- /dev/null +++ b/src/quickcontrols/windows/Switch.qml @@ -0,0 +1,37 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls.Windows.impl + +T.Switch { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + padding: 6 + spacing: 6 + + readonly property bool __notCustomizable: true + readonly property Item __focusFrameTarget: indicator + readonly property Item __focusFrameStyleItem: indicator + + indicator: SwitchIndicator {} + + contentItem: Text { + leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0 + rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0 + text: control.text + font: control.font + color: control.palette.windowText + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + + readonly property bool __ignoreNotCustomizable: true + } +} diff --git a/src/quickcontrols/windows/SwitchDelegate.qml b/src/quickcontrols/windows/SwitchDelegate.qml new file mode 100644 index 0000000000..0130a9b372 --- /dev/null +++ b/src/quickcontrols/windows/SwitchDelegate.qml @@ -0,0 +1,45 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T +import QtQuick.Controls.Windows.impl +import QtQuick.NativeStyle as NativeStyle + +T.SwitchDelegate { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + padding: 6 + spacing: 6 + + readonly property bool __notCustomizable: true + readonly property Item __focusFrameTarget: indicator + readonly property Item __focusFrameStyleItem: indicator + + indicator: SwitchIndicator { + x: control.text + ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) + : control.leftPadding + (control.availableWidth - width) / 2 + } + + contentItem: NativeStyle.DefaultItemDelegateIconLabel { + color: control.highlighted ? control.palette.button : control.palette.windowText + + readonly property bool __ignoreNotCustomizable: true + } + + background: Rectangle { + implicitWidth: 100 + implicitHeight: 20 + color: Qt.darker(control.highlighted + ? control.palette.highlight : control.palette.button, control.down ? 1.05 : 1) + + readonly property bool __ignoreNotCustomizable: true + } +} diff --git a/src/quickcontrols/windows/images/checkmark.png b/src/quickcontrols/windows/images/checkmark.png Binary files differnew file mode 100644 index 0000000000..35fe52c8c0 --- /dev/null +++ b/src/quickcontrols/windows/images/checkmark.png diff --git a/src/quickcontrols/windows/images/checkmark@2x.png b/src/quickcontrols/windows/images/checkmark@2x.png Binary files differnew file mode 100644 index 0000000000..fb7096b4b5 --- /dev/null +++ b/src/quickcontrols/windows/images/checkmark@2x.png diff --git a/src/quickcontrols/windows/images/checkmark@3x.png b/src/quickcontrols/windows/images/checkmark@3x.png Binary files differnew file mode 100644 index 0000000000..e0c2790607 --- /dev/null +++ b/src/quickcontrols/windows/images/checkmark@3x.png diff --git a/src/quickcontrols/windows/images/menuarrow.png b/src/quickcontrols/windows/images/menuarrow.png Binary files differnew file mode 100644 index 0000000000..b504351fe1 --- /dev/null +++ b/src/quickcontrols/windows/images/menuarrow.png diff --git a/src/quickcontrols/windows/images/menuarrow@2x.png b/src/quickcontrols/windows/images/menuarrow@2x.png Binary files differnew file mode 100644 index 0000000000..fa9082d0c0 --- /dev/null +++ b/src/quickcontrols/windows/images/menuarrow@2x.png diff --git a/src/quickcontrols/windows/images/menuarrow@3x.png b/src/quickcontrols/windows/images/menuarrow@3x.png Binary files differnew file mode 100644 index 0000000000..acb626246d --- /dev/null +++ b/src/quickcontrols/windows/images/menuarrow@3x.png diff --git a/src/quickcontrols/windows/impl/CMakeLists.txt b/src/quickcontrols/windows/impl/CMakeLists.txt new file mode 100644 index 0000000000..8b031b7a8d --- /dev/null +++ b/src/quickcontrols/windows/impl/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +set(qml_files + "CheckIndicator.qml" + "SwitchIndicator.qml" +) + +qt_internal_add_qml_module(QuickControls2WindowsStyleImpl + URI "QtQuick.Controls.Windows.impl" + VERSION "${PROJECT_VERSION}" + PAST_MAJOR_VERSIONS 6 + CLASS_NAME QtQuickControls2WindowsStyleImplPlugin + DEPENDENCIES + QtQuick/auto + PLUGIN_TARGET qtquickcontrols2windowsstyleimplplugin + QML_FILES + ${qml_files} + DEFINES + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII +) diff --git a/src/quickcontrols/windows/impl/CheckIndicator.qml b/src/quickcontrols/windows/impl/CheckIndicator.qml new file mode 100644 index 0000000000..818336dfdf --- /dev/null +++ b/src/quickcontrols/windows/impl/CheckIndicator.qml @@ -0,0 +1,21 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Controls.impl + +Item { + id: indicator + implicitWidth: 14 + implicitHeight: 10 + + property Item control + + ColorImage { + y: (parent.height - height) / 2 + color: control.palette.text + source: "qrc:/qt-project.org/imports/QtQuick/Controls/Windows/images/checkmark.png" + visible: indicator.control.checkState === Qt.Checked + || (indicator.control.checked && indicator.control.checkState === undefined) + } +} diff --git a/src/quickcontrols/windows/impl/SwitchIndicator.qml b/src/quickcontrols/windows/impl/SwitchIndicator.qml new file mode 100644 index 0000000000..0dd80dadf7 --- /dev/null +++ b/src/quickcontrols/windows/impl/SwitchIndicator.qml @@ -0,0 +1,59 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Templates as T + +Rectangle { + id: root + x: control.text ? (control.mirrored + ? control.width - width - control.rightPadding : control.leftPadding) + : control.leftPadding + (control.availableWidth - width) / 2 + y: control.topPadding + (control.availableHeight - height) / 2 + implicitWidth: 40 + implicitHeight: 16 + radius: 3 + color: Qt.darker(control.palette.button, control.down ? 1.2 : 1.1) + border.color: Qt.darker(control.palette.window, 1.4) + + readonly property bool __ignoreNotCustomizable: true + readonly property real __focusFrameRadius: 2 + readonly property T.AbstractButton control: parent as T.AbstractButton + + // Checked indicator. + Rectangle { + x: root.control.mirrored ? parent.children[1].x : 0 + width: root.control.mirrored + ? parent.width - parent.children[1].x : parent.children[1].x + parent.children[1].width + height: parent.height + radius: 3 + color: Qt.darker(root.control.palette.highlight, root.control.down ? 1.1 : 1) + border.color: Qt.darker(root.control.palette.highlight, 1.35) + border.width: root.control.enabled ? 1 : 0 + opacity: root.control.checked ? 1 : 0 + + Behavior on opacity { + enabled: !root.control.down + NumberAnimation { duration: 80 } + } + } + + // Handle. + Rectangle { + x: Math.max(0, Math.min(parent.width - width, + root.control.visualPosition * parent.width - (width / 2))) + y: (parent.height - height) / 2 + width: 20 + height: 16 + radius: 3 + color: Qt.lighter(root.control.palette.button, root.control.down + ? 1 : (root.control.hovered ? 1.07 : 1.045)) + border.width: 1 + border.color: Qt.darker(root.control.palette.window, 1.4) + + Behavior on x { + enabled: !root.control.down + SmoothedAnimation { velocity: 200 } + } + } +} |