diff options
Diffstat (limited to 'src/quicknativestyle')
39 files changed, 680 insertions, 276 deletions
diff --git a/src/quicknativestyle/CMakeLists.txt b/src/quicknativestyle/CMakeLists.txt index a1c1739d40..c5056d33b7 100644 --- a/src/quicknativestyle/CMakeLists.txt +++ b/src/quicknativestyle/CMakeLists.txt @@ -7,22 +7,27 @@ set(qml_files "controls/DefaultButton.qml" - "controls/DefaultSlider.qml" - "controls/DefaultGroupBox.qml" "controls/DefaultCheckBox.qml" + "controls/DefaultComboBox.qml" + "controls/DefaultDial.qml" + "controls/DefaultFrame.qml" + "controls/DefaultGroupBox.qml" + "controls/DefaultItemDelegate.qml" + "controls/DefaultItemDelegateIconLabel.qml" + "controls/DefaultProgressBar.qml" "controls/DefaultRadioButton.qml" + "controls/DefaultRadioDelegate.qml" + "controls/DefaultScrollBar.qml" + "controls/DefaultSlider.qml" "controls/DefaultSpinBox.qml" - "controls/DefaultTextField.qml" - "controls/DefaultFrame.qml" "controls/DefaultTextArea.qml" - "controls/DefaultComboBox.qml" - "controls/DefaultScrollBar.qml" - "controls/DefaultProgressBar.qml" - "controls/DefaultDial.qml" + "controls/DefaultTextField.qml" ) if(MACOS) - list(APPEND qml_files "util/FocusFrame.qml") + list(APPEND qml_files "util/MacFocusFrame.qml") +elseif(WIN32) + list(APPEND qml_files "util/WindowsFocusFrame.qml") endif() if(QT_FEATURE_quick_treeview) @@ -45,12 +50,14 @@ qt_internal_add_qml_module(qtquickcontrols2nativestyleplugin items/qquickstyleitem.cpp items/qquickstyleitem.h items/qquickstyleitembutton.cpp items/qquickstyleitembutton.h items/qquickstyleitemcheckbox.cpp items/qquickstyleitemcheckbox.h - items/qquickstyleitemcombobox.cpp items/qquickstyleitemcombobox.h + items/qquickstyleitemdelaybutton.cpp items/qquickstyleitemdelaybutton.h + items/qquickstyleitemcheckdelegate.cpp items/qquickstyleitemcheckdelegate.h items/qquickstyleitemdial.cpp items/qquickstyleitemdial.h items/qquickstyleitemframe.cpp items/qquickstyleitemframe.h items/qquickstyleitemgroupbox.cpp items/qquickstyleitemgroupbox.h items/qquickstyleitemprogressbar.cpp items/qquickstyleitemprogressbar.h items/qquickstyleitemradiobutton.cpp items/qquickstyleitemradiobutton.h + items/qquickstyleitemradiodelegate.cpp items/qquickstyleitemradiodelegate.h items/qquickstyleitemscrollbar.cpp items/qquickstyleitemscrollbar.h items/qquickstyleitemslider.cpp items/qquickstyleitemslider.h items/qquickstyleitemspinbox.cpp items/qquickstyleitemspinbox.h @@ -63,6 +70,7 @@ qt_internal_add_qml_module(qtquickcontrols2nativestyleplugin qstyle/qquickstylehelper.cpp qstyle/qquickstylehelper_p.h qstyle/qquickstyleoption.cpp qstyle/qquickstyleoption.h qtquickcontrols2nativestyleplugin.cpp + util/qquickfocusframe.cpp util/qquickfocusframe.h QML_FILES ${qml_files} DEFINES @@ -86,6 +94,11 @@ qt_internal_extend_target(qtquickcontrols2nativestyleplugin CONDITION QT_FEATURE items/qquickstyleitemtreeindicator.cpp items/qquickstyleitemtreeindicator.h ) +qt_internal_extend_target(qtquickcontrols2nativestyleplugin CONDITION QT_FEATURE_qml_delegate_model + SOURCES + items/qquickstyleitemcombobox.cpp items/qquickstyleitemcombobox.h +) + qt_internal_extend_target(qtquickcontrols2nativestyleplugin CONDITION MACOS SOURCES items/qquickstyleitemscrollviewcorner.cpp items/qquickstyleitemscrollviewcorner.h @@ -105,6 +118,7 @@ qt_internal_extend_target(qtquickcontrols2nativestyleplugin CONDITION WIN32 qstyle/windows/qquickwindowsxpstyle.cpp qstyle/windows/qquickwindowsxpstyle_p.h qstyle/windows/qquickwindowsxpstyle_p_p.h + util/qquickwindowsfocusframe.cpp util/qquickwindowsfocusframe.h INCLUDE_DIRECTORIES qstyle/windows LIBRARIES diff --git a/src/quicknativestyle/controls/DefaultComboBox.qml b/src/quicknativestyle/controls/DefaultComboBox.qml index a9a820a2d1..0876c522b3 100644 --- a/src/quicknativestyle/controls/DefaultComboBox.qml +++ b/src/quicknativestyle/controls/DefaultComboBox.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/quicknativestyle/controls/DefaultItemDelegate.qml b/src/quicknativestyle/controls/DefaultItemDelegate.qml new file mode 100644 index 0000000000..55c54dbca5 --- /dev/null +++ b/src/quicknativestyle/controls/DefaultItemDelegate.qml @@ -0,0 +1,32 @@ +// 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.impl +import QtQuick.NativeStyle as NativeStyle + +T.ItemDelegate { + 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 + + icon.width: 16 + icon.height: 16 + + contentItem: NativeStyle.DefaultItemDelegateIconLabel {} + + background: Rectangle { + implicitWidth: 100 + implicitHeight: 20 + color: Qt.darker(control.highlighted + ? control.palette.highlight : control.palette.button, control.down ? 1.05 : 1) + } +} diff --git a/src/quicknativestyle/controls/DefaultItemDelegateIconLabel.qml b/src/quicknativestyle/controls/DefaultItemDelegateIconLabel.qml new file mode 100644 index 0000000000..7ac31e9f3e --- /dev/null +++ b/src/quicknativestyle/controls/DefaultItemDelegateIconLabel.qml @@ -0,0 +1,21 @@ +// 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.Controls.impl +import QtQuick.Templates as T + +IconLabel { + text: control.text + font: control.font + icon: control.icon + color: control.palette.windowText + spacing: control.spacing + mirrored: control.mirrored + display: control.display + alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon + ? Qt.AlignCenter : Qt.AlignLeft + leftPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0 + rightPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0 + + readonly property T.ItemDelegate control: parent as T.ItemDelegate +} diff --git a/src/quicknativestyle/controls/DefaultProgressBar.qml b/src/quicknativestyle/controls/DefaultProgressBar.qml index 77dd4741b1..0b318a5635 100644 --- a/src/quicknativestyle/controls/DefaultProgressBar.qml +++ b/src/quicknativestyle/controls/DefaultProgressBar.qml @@ -14,10 +14,9 @@ T.ProgressBar { implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding, - control.horizontal ? 90 : 0 /* minimum */ ) + 90) implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, - implicitContentHeight + topPadding + bottomPadding, - control.vertical ? 90 : 0 /* minimum */ ) + implicitContentHeight + topPadding + bottomPadding) background: NativeStyle.ProgressBar { control: control diff --git a/src/quicknativestyle/controls/DefaultRadioDelegate.qml b/src/quicknativestyle/controls/DefaultRadioDelegate.qml new file mode 100644 index 0000000000..82bc0d26bf --- /dev/null +++ b/src/quicknativestyle/controls/DefaultRadioDelegate.qml @@ -0,0 +1,54 @@ +// 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.impl +import QtQuick.NativeStyle as NativeStyle + +T.RadioDelegate { + 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 + + icon.width: 16 + icon.height: 16 + + contentItem: NativeStyle.DefaultItemDelegateIconLabel { + readonly property bool __ignoreNotCustomizable: true + } + + indicator: NativeStyle.RadioDelegate { + x: control.text + ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) + : control.leftPadding + (control.availableWidth - width) / 2 + y: control.topPadding + Math.round((control.availableHeight - height) / 2) + contentWidth: control.implicitContentWidth + contentHeight: control.implicitContentHeight + useNinePatchImage: false + control: control + + 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/quicknativestyle/controls/DefaultScrollBar.qml b/src/quicknativestyle/controls/DefaultScrollBar.qml index 7394dd1e74..1fad8e9a41 100644 --- a/src/quicknativestyle/controls/DefaultScrollBar.qml +++ b/src/quicknativestyle/controls/DefaultScrollBar.qml @@ -17,7 +17,7 @@ T.ScrollBar { implicitContentHeight + topPadding + bottomPadding) visible: policy === T.ScrollBar.AlwaysOn || (policy === T.ScrollBar.AsNeeded && size < 1.0) - minimumSize: !__nativeContentItem ? 10 : orientation === Qt.Vertical ? + minimumSize: !__nativeContentItem ? 0.1 : orientation === Qt.Vertical ? contentItem.minimumSize.height / height : contentItem.minimumSize.width / width background: NativeStyle.ScrollBar { diff --git a/src/quicknativestyle/controls/DefaultTextArea.qml b/src/quicknativestyle/controls/DefaultTextArea.qml index 4ed9427bab..faab250fae 100644 --- a/src/quicknativestyle/controls/DefaultTextArea.qml +++ b/src/quicknativestyle/controls/DefaultTextArea.qml @@ -34,8 +34,8 @@ T.TextArea { id: placeholder x: control.leftPadding y: control.topPadding - width: control.availableWidth - height: control.availableHeight + width: control.width - (control.leftPadding + control.rightPadding) + height: control.height - (control.topPadding + control.bottomPadding) text: control.placeholderText font: control.font color: control.placeholderTextColor diff --git a/src/quicknativestyle/controls/DefaultTreeViewDelegate.qml b/src/quicknativestyle/controls/DefaultTreeViewDelegate.qml index a15b4d36f1..89130947bb 100644 --- a/src/quicknativestyle/controls/DefaultTreeViewDelegate.qml +++ b/src/quicknativestyle/controls/DefaultTreeViewDelegate.qml @@ -69,6 +69,7 @@ T.TreeViewDelegate { // The edit delegate is a separate component, and doesn't need // to follow the same strict rules that are applied to a control. // qmllint disable attached-property-reuse + // qmllint disable controls-attached-property-reuse // qmllint disable controls-sanity TableView.editDelegate: FocusScope { width: parent.width @@ -76,7 +77,7 @@ T.TreeViewDelegate { readonly property int __role: { let model = control.treeView.model - let index = control.treeView.modelIndex(column, row) + let index = control.treeView.index(row, column) let editText = model.data(index, Qt.EditRole) return editText !== undefined ? Qt.EditRole : Qt.DisplayRole } @@ -86,17 +87,18 @@ T.TreeViewDelegate { x: control.contentItem.x y: (parent.height - height) / 2 width: control.contentItem.width - text: control.treeView.model.data(control.treeView.modelIndex(column, row), __role) + text: control.treeView.model.data(control.treeView.index(row, column), __role) focus: true } TableView.onCommit: { - let index = TableView.view.modelIndex(column, row) + let index = TableView.view.index(row, column) TableView.view.model.setData(index, textField.text, __role) } Component.onCompleted: textField.selectAll() } // qmllint enable attached-property-reuse + // qmllint enable controls-attached-property-reuse // qmllint enable controls-sanity } diff --git a/src/quicknativestyle/items/qquickstyleitem.h b/src/quicknativestyle/items/qquickstyleitem.h index 1ad8932d23..3d04371b7e 100644 --- a/src/quicknativestyle/items/qquickstyleitem.h +++ b/src/quicknativestyle/items/qquickstyleitem.h @@ -14,6 +14,8 @@ #include "qquickstyle.h" #include "qquickstyleoption.h" +#include <QtCore/qpointer.h> + // Work-around for now, to avoid creator getting confused // about missing macros. Should eventually be defined // in qt declarative somewhere I assume. @@ -274,6 +276,4 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickStyleItem::DebugFlags) QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickStyleItem) - #endif // QQUICKSTYLEITEM_H diff --git a/src/quicknativestyle/items/qquickstyleitembutton.h b/src/quicknativestyle/items/qquickstyleitembutton.h index 668013ac6f..82dff23048 100644 --- a/src/quicknativestyle/items/qquickstyleitembutton.h +++ b/src/quicknativestyle/items/qquickstyleitembutton.h @@ -23,7 +23,7 @@ protected: StyleItemGeometry calculateGeometry() override; private: - void initStyleOption(QStyleOptionButton &styleOption) const; + virtual void initStyleOption(QStyleOptionButton &styleOption) const; }; QT_END_NAMESPACE diff --git a/src/quicknativestyle/items/qquickstyleitemcheckbox.h b/src/quicknativestyle/items/qquickstyleitemcheckbox.h index 92cda579ef..f50c621d12 100644 --- a/src/quicknativestyle/items/qquickstyleitemcheckbox.h +++ b/src/quicknativestyle/items/qquickstyleitemcheckbox.h @@ -23,7 +23,7 @@ protected: StyleItemGeometry calculateGeometry() override; private: - void initStyleOption(QStyleOptionButton &styleOption) const; + virtual void initStyleOption(QStyleOptionButton &styleOption) const; }; QT_END_NAMESPACE diff --git a/src/quicknativestyle/items/qquickstyleitemcheckdelegate.cpp b/src/quicknativestyle/items/qquickstyleitemcheckdelegate.cpp new file mode 100644 index 0000000000..22576c50d2 --- /dev/null +++ b/src/quicknativestyle/items/qquickstyleitemcheckdelegate.cpp @@ -0,0 +1,32 @@ +// 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 + +#include "qquickstyleitemcheckdelegate.h" + +#include <QtQuickTemplates2/private/qquickcheckdelegate_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickStyleItemCheckDelegate::connectToControl() const +{ + QQuickStyleItem::connectToControl(); + auto checkDelegate = control<QQuickCheckDelegate>(); + connect(checkDelegate, &QQuickCheckDelegate::downChanged, this, &QQuickStyleItem::markImageDirty); + connect(checkDelegate, &QQuickCheckDelegate::checkStateChanged, this, &QQuickStyleItem::markImageDirty); +} + +void QQuickStyleItemCheckDelegate::initStyleOption(QStyleOptionButton &styleOption) const +{ + initStyleOptionBase(styleOption); + auto checkDelegate = control<QQuickCheckDelegate>(); + + styleOption.state |= checkDelegate->isDown() ? QStyle::State_Sunken : QStyle::State_Raised; + if (checkDelegate->isTristate() && checkDelegate->checkState() == Qt::PartiallyChecked) + styleOption.state |= QStyle::State_NoChange; + else + styleOption.state |= checkDelegate->isChecked() ? QStyle::State_On : QStyle::State_Off; +} + +QT_END_NAMESPACE + +#include "moc_qquickstyleitemcheckdelegate.cpp" diff --git a/src/quicknativestyle/items/qquickstyleitemcheckdelegate.h b/src/quicknativestyle/items/qquickstyleitemcheckdelegate.h new file mode 100644 index 0000000000..27ff42de25 --- /dev/null +++ b/src/quicknativestyle/items/qquickstyleitemcheckdelegate.h @@ -0,0 +1,25 @@ +// 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 + +#ifndef QQUICKSTYLEITEMCHECKDELEGATE_H +#define QQUICKSTYLEITEMCHECKDELEGATE_H + +#include "qquickstyleitemcheckbox.h" + +QT_BEGIN_NAMESPACE + +class QQuickStyleItemCheckDelegate : public QQuickStyleItemCheckBox +{ + Q_OBJECT + QML_NAMED_ELEMENT(CheckDelegate) + +protected: + void connectToControl() const override; + +private: + void initStyleOption(QStyleOptionButton &styleOption) const override; +}; + +QT_END_NAMESPACE + +#endif // QQUICKSTYLEITEMCHECKDELEGATE_H diff --git a/src/quicknativestyle/items/qquickstyleitemdelaybutton.cpp b/src/quicknativestyle/items/qquickstyleitemdelaybutton.cpp new file mode 100644 index 0000000000..19309d11b6 --- /dev/null +++ b/src/quicknativestyle/items/qquickstyleitemdelaybutton.cpp @@ -0,0 +1,28 @@ +// 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 + +#include "qquickstyleitemdelaybutton.h" + +#include <QtQuickTemplates2/private/qquickdelaybutton_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickStyleItemDelayButton::connectToControl() const +{ + QQuickStyleItem::connectToControl(); + auto button = control<QQuickDelayButton>(); + connect(button, &QQuickButton::downChanged, this, &QQuickStyleItem::markImageDirty); + connect(button, &QQuickButton::checkedChanged, this, &QQuickStyleItem::markImageDirty); +} + +void QQuickStyleItemDelayButton::initStyleOption(QStyleOptionButton &styleOption) const +{ + initStyleOptionBase(styleOption); + auto button = control<QQuickDelayButton>(); + + styleOption.state |= button->isDown() ? QStyle::State_Sunken : QStyle::State_Raised; +} + +QT_END_NAMESPACE + +#include "moc_qquickstyleitemdelaybutton.cpp" diff --git a/src/quicknativestyle/items/qquickstyleitemdelaybutton.h b/src/quicknativestyle/items/qquickstyleitemdelaybutton.h new file mode 100644 index 0000000000..e2a0bf2174 --- /dev/null +++ b/src/quicknativestyle/items/qquickstyleitemdelaybutton.h @@ -0,0 +1,25 @@ +// 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 + +#ifndef QQUICKSTYLEITEMDELAYBUTTON_H +#define QQUICKSTYLEITEMDELAYBUTTON_H + +#include "qquickstyleitembutton.h" + +QT_BEGIN_NAMESPACE + +class QQuickStyleItemDelayButton : public QQuickStyleItemButton +{ + Q_OBJECT + QML_NAMED_ELEMENT(DelayButton) + +protected: + void connectToControl() const override; + +private: + void initStyleOption(QStyleOptionButton &styleOption) const override; +}; + +QT_END_NAMESPACE + +#endif // QQUICKSTYLEITEMDELAYBUTTON_H diff --git a/src/quicknativestyle/items/qquickstyleitemdial.cpp b/src/quicknativestyle/items/qquickstyleitemdial.cpp index e2407e9e81..fe36f866e4 100644 --- a/src/quicknativestyle/items/qquickstyleitemdial.cpp +++ b/src/quicknativestyle/items/qquickstyleitemdial.cpp @@ -19,6 +19,8 @@ void QQuickStyleItemDial::connectToControl() const connect(dial, &QQuickDial::positionChanged, this, &QQuickStyleItem::markImageDirty); connect(dial, &QQuickDial::valueChanged, this, &QQuickStyleItem::markImageDirty); connect(dial, &QQuickDial::stepSizeChanged, this, &QQuickStyleItem::markImageDirty); + connect(dial, &QQuickDial::startAngleChanged, this, &QQuickStyleItem::markImageDirty); + connect(dial, &QQuickDial::endAngleChanged, this, &QQuickStyleItem::markImageDirty); connect(dial, &QQuickDial::pressedChanged, this, &QQuickStyleItem::markImageDirty); } @@ -54,6 +56,8 @@ void QQuickStyleItemDial::initStyleOption(QStyleOptionSlider &styleOption) const styleOption.tickInterval = dial->stepSize(); styleOption.dialWrapping = dial->wrap(); styleOption.upsideDown = true; + styleOption.startAngle = dial->startAngle(); + styleOption.endAngle = dial->endAngle(); if (dial->isPressed()) styleOption.state |= QStyle::State_Sunken; diff --git a/src/quicknativestyle/items/qquickstyleitemradiobutton.h b/src/quicknativestyle/items/qquickstyleitemradiobutton.h index 4674098116..209d2cc65f 100644 --- a/src/quicknativestyle/items/qquickstyleitemradiobutton.h +++ b/src/quicknativestyle/items/qquickstyleitemradiobutton.h @@ -23,7 +23,7 @@ protected: StyleItemGeometry calculateGeometry() override; private: - void initStyleOption(QStyleOptionButton &styleOption) const; + virtual void initStyleOption(QStyleOptionButton &styleOption) const; }; QT_END_NAMESPACE diff --git a/src/quicknativestyle/items/qquickstyleitemradiodelegate.cpp b/src/quicknativestyle/items/qquickstyleitemradiodelegate.cpp new file mode 100644 index 0000000000..a4325cfe15 --- /dev/null +++ b/src/quicknativestyle/items/qquickstyleitemradiodelegate.cpp @@ -0,0 +1,29 @@ +// 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 + +#include "qquickstyleitemradiodelegate.h" + +#include <QtQuickTemplates2/private/qquickradiodelegate_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickStyleItemRadioDelegate::connectToControl() const +{ + QQuickStyleItem::connectToControl(); + auto radioDelegate = control<QQuickRadioDelegate>(); + connect(radioDelegate, &QQuickRadioDelegate::downChanged, this, &QQuickStyleItem::markImageDirty); + connect(radioDelegate, &QQuickRadioDelegate::checkedChanged, this, &QQuickStyleItem::markImageDirty); +} + +void QQuickStyleItemRadioDelegate::initStyleOption(QStyleOptionButton &styleOption) const +{ + initStyleOptionBase(styleOption); + auto radioDelegate = control<QQuickRadioDelegate>(); + + styleOption.state |= radioDelegate->isDown() ? QStyle::State_Sunken : QStyle::State_Raised; + styleOption.state |= radioDelegate->isChecked() ? QStyle::State_On : QStyle::State_Off; +} + +QT_END_NAMESPACE + +#include "moc_qquickstyleitemradiodelegate.cpp" diff --git a/src/quicknativestyle/items/qquickstyleitemradiodelegate.h b/src/quicknativestyle/items/qquickstyleitemradiodelegate.h new file mode 100644 index 0000000000..3661ce792e --- /dev/null +++ b/src/quicknativestyle/items/qquickstyleitemradiodelegate.h @@ -0,0 +1,25 @@ +// 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 + +#ifndef QQUICKSTYLEITEMRADIODELEGATE_H +#define QQUICKSTYLEITEMRADIODELEGATE_H + +#include "qquickstyleitemradiobutton.h" + +QT_BEGIN_NAMESPACE + +class QQuickStyleItemRadioDelegate : public QQuickStyleItemRadioButton +{ + Q_OBJECT + QML_NAMED_ELEMENT(RadioDelegate) + +protected: + void connectToControl() const override; + +private: + void initStyleOption(QStyleOptionButton &styleOption) const override; +}; + +QT_END_NAMESPACE + +#endif // QQUICKSTYLEITEMRADIODELEGATE_H diff --git a/src/quicknativestyle/items/qquickstyleitemscrollbar.cpp b/src/quicknativestyle/items/qquickstyleitemscrollbar.cpp index c328ab6d1f..097341eb56 100644 --- a/src/quicknativestyle/items/qquickstyleitemscrollbar.cpp +++ b/src/quicknativestyle/items/qquickstyleitemscrollbar.cpp @@ -5,6 +5,14 @@ QT_BEGIN_NAMESPACE +QQuickStyleItemScrollBar::QQuickStyleItemScrollBar(QQuickItem *parent) + : QQuickStyleItem(parent) +{ +#ifdef QT_DEBUG + setObjectName("styleItemScrollBar"); +#endif +} + QFont QQuickStyleItemScrollBar::styleFont(QQuickItem *control) const { return style()->font(QStyle::CE_ProgressBarLabel, controlSize(control)); diff --git a/src/quicknativestyle/items/qquickstyleitemscrollbar.h b/src/quicknativestyle/items/qquickstyleitemscrollbar.h index 6ef232420f..57a9c19059 100644 --- a/src/quicknativestyle/items/qquickstyleitemscrollbar.h +++ b/src/quicknativestyle/items/qquickstyleitemscrollbar.h @@ -26,6 +26,8 @@ public: }; Q_ENUM(SubControl) + explicit QQuickStyleItemScrollBar(QQuickItem *parent = nullptr); + QFont styleFont(QQuickItem *control) const override; protected: diff --git a/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm index eb777ea9f2..b92c380657 100644 --- a/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm +++ b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm @@ -166,45 +166,6 @@ const int QMacStylePrivate::PushButtonContentPadding = 6; QVector<QPointer<QObject> > QMacStylePrivate::scrollBars; -// Title bar gradient colors for Lion were determined by inspecting PSDs exported -// using CoreUI's CoreThemeDocument; there is no public API to retrieve them - -static QLinearGradient titlebarGradientActive() -{ - static QLinearGradient darkGradient = [](){ - QLinearGradient gradient; - // FIXME: colors are chosen somewhat arbitrarily and could be fine-tuned, - // or ideally determined by calling a native API. - gradient.setColorAt(0, QColor(47, 47, 47)); - return gradient; - }(); - static QLinearGradient lightGradient = [](){ - QLinearGradient gradient; - gradient.setColorAt(0, QColor(235, 235, 235)); - gradient.setColorAt(0.5, QColor(210, 210, 210)); - gradient.setColorAt(0.75, QColor(195, 195, 195)); - gradient.setColorAt(1, QColor(180, 180, 180)); - return gradient; - }(); - return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient; -} - -static QLinearGradient titlebarGradientInactive() -{ - static QLinearGradient darkGradient = [](){ - QLinearGradient gradient; - gradient.setColorAt(1, QColor(42, 42, 42)); - return gradient; - }(); - static QLinearGradient lightGradient = [](){ - QLinearGradient gradient; - gradient.setColorAt(0, QColor(250, 250, 250)); - gradient.setColorAt(1, QColor(225, 225, 225)); - return gradient; - }(); - return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient; -} - static const QColor titlebarSeparatorLineActive(111, 111, 111); static const QColor titlebarSeparatorLineInactive(131, 131, 131); static const QColor darkModeSeparatorLine(88, 88, 88); @@ -2041,20 +2002,21 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt) const ret = 1; break; case PM_ScrollView_ScrollBarOverlap: - ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay ? - pixelMetric(PM_ScrollBarExtent, opt) : 0; + ret = styleHint(SH_ScrollBar_Transient, opt, nullptr) + ? pixelMetric(PM_ScrollBarExtent, opt) + : 0; break; case PM_PushButtonFocusFrameRadius: - ret = LargeSmallMini(opt, 8, 7, 5); + ret = LargeSmallMini(opt, 5, 4, 2); break; case PM_CheckBoxFocusFrameRadius: - ret = LargeSmallMini(opt, 6, 5, 4); + ret = LargeSmallMini(opt, 3, 2, 1); break; case PM_ComboBoxFocusFrameRadius: - ret = LargeSmallMini(opt, 8, 7, 4); + ret = LargeSmallMini(opt, 5, 4, 1); break; case PM_RadioButtonFocusFrameRadius: - ret = 10; + ret = 7; break; case PM_SliderFocusFrameRadius: // QTBUG-93423: We currently need to skip drawing a focus ring around the handle, since @@ -2067,7 +2029,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt) const case PM_SpinBoxFocusFrameRadius: case PM_TextAreaFocusFrameRadius: case PM_TextFieldFocusFrameRadius: - ret = 3; + ret = 0; break; default: ret = QCommonStyle::pixelMetric(metric, opt); @@ -2277,7 +2239,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, QStyleHintReturn ++srow; } } - QBitmap qmask = QBitmap::fromImage(img_mask); + QBitmap qmask = QBitmap::fromImage(std::move(img_mask)); mask->region = QRegion(qmask); } break; } @@ -2878,20 +2840,10 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai // } break; //#endif // QT_CONFIG(tabbar) case PE_PanelStatusBar: { - // Fill the status bar with the titlebar gradient. - QLinearGradient linearGrad; - const bool isMainWindow = qt_macWindowMainWindow(opt->window); - if (isMainWindow) - linearGrad = titlebarGradientActive(); - else - linearGrad = titlebarGradientInactive(); - - linearGrad.setStart(0, opt->rect.top()); - linearGrad.setFinalStop(0, opt->rect.bottom()); - p->fillRect(opt->rect, linearGrad); + p->fillRect(opt->rect, opt->palette.window()); // Draw the black separator line at the top of the status bar. - if (isMainWindow) + if (qt_macWindowMainWindow(opt->window)) p->setPen(titlebarSeparatorLineActive); else p->setPen(titlebarSeparatorLineInactive); @@ -3496,12 +3448,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } // fill title bar background - QLinearGradient linearGrad; - linearGrad.setStart(QPointF(0, 0)); - linearGrad.setFinalStop(QPointF(0, 2 * effectiveRect.height())); - linearGrad.setColorAt(0, opt->palette.button().color()); - linearGrad.setColorAt(1, opt->palette.dark().color()); - p->fillRect(effectiveRect, linearGrad); + p->fillRect(effectiveRect, opt->palette.window()); // draw horizontal line at bottom p->setPen(opt->palette.dark().color()); @@ -4859,16 +4806,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF(); const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0); QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect); - if (isActive) { - QLinearGradient g; - g.setStart(QPointF(0, 0)); - g.setFinalStop(QPointF(0, 2 * opt->rect.height())); - g.setColorAt(0, opt->palette.button().color()); - g.setColorAt(1, opt->palette.dark().color()); - p->fillPath(innerFramePath, g); - } else { - p->fillPath(innerFramePath, opt->palette.button()); - } + p->fillPath(innerFramePath, opt->palette.button()); if (titlebar->subControls & (SC_TitleBarCloseButton | SC_TitleBarMaxButton diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp index d8cac57486..02bd1a694c 100644 --- a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp +++ b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp @@ -24,7 +24,9 @@ #include <qtextformat.h> #include <qfileinfo.h> #include <qdir.h> +#if QT_CONFIG(settings) #include <qsettings.h> +#endif #include <qvariant.h> #include <qpixmapcache.h> #include <qmatrix4x4.h> @@ -502,6 +504,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q proxy()->drawPrimitive(PE_FrameLineEdit, panel, p); } break; +#if QT_CONFIG(quick_itemview) case PE_IndicatorColumnViewArrow: { if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { bool reverse = (viewOpt->direction == Qt::RightToLeft); @@ -595,6 +598,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q } } break; +#endif // QT_CONFIG(quick_itemview) case PE_PanelScrollAreaCorner: { const QBrush brush(opt->palette.brush(QPalette::Window)); p->fillRect(opt->rect, brush); @@ -665,7 +669,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q imagePainter.drawPolygon(a); imagePainter.end(); - pixmap = QPixmap::fromImage(image); + pixmap = QPixmap::fromImage(std::move(image)); pixmap.setDevicePixelRatio(pixelRatio); QPixmapCache::insert(pixmapName, pixmap); } @@ -811,6 +815,7 @@ QString QCommonStylePrivate::calculateElidedText(const QString &text, const QTex return ret; } +#if QT_CONFIG(quick_itemview) QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int role) const { switch (role) { @@ -1028,6 +1033,7 @@ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItem *opt, QRect *textRect = display; } } +#endif // QT_CONFIG(quick_itemview) QString QCommonStylePrivate::toolButtonElideText(const QStyleOptionToolButton *option, const QRect &textRect, int flags) const @@ -2034,6 +2040,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, p->drawLine(line2starting, top, line2starting, bottom); } break; +#if QT_CONFIG(quick_itemview) case CE_ItemViewItem: if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { p->save(); @@ -2112,6 +2119,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, p->restore(); } break; +#endif // QT_CONFIG(quick_itemview) case CE_ShapedFrame: if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { int frameShape = f->frameShape; @@ -2828,6 +2836,7 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt) const } break; } +#if QT_CONFIG(quick_itemview) case SE_ItemViewItemCheckIndicator: if (!qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { r = subElementRect(SE_CheckBoxIndicator, opt); @@ -2854,6 +2863,7 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt) const r = d->displayRect; } break; +#endif // QT_CONFIG(quick_itemview) case SE_ToolBarHandle: if (const QStyleOptionToolBar *tbopt = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) { if (tbopt->features & QStyleOptionToolBar::Movable) { @@ -2898,14 +2908,13 @@ static StaticPolygonF<3> calcArrow(const QStyleOptionSlider *dial, qreal &a) int r = qMin(width, height) / 2; int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition); + qreal startAngle = (90. - dial->startAngle) * Q_PI / 180.; + qreal spanAngle = (dial->endAngle - dial->startAngle) * Q_PI / 180.; if (dial->maximum == dial->minimum) a = Q_PI / 2; - else if (dial->dialWrapping) - a = Q_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Q_PI - / (dial->maximum - dial->minimum); else - a = (Q_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * Q_PI - / (dial->maximum - dial->minimum)) / 6; + a = (startAngle - (currentSliderPosition - dial->minimum) * spanAngle + / (dial->maximum - dial->minimum)); int xc = width / 2; int yc = height / 2; @@ -3865,6 +3874,7 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex break; case SC_SpinBoxFrame: ret = spinbox->rect; + break; default: break; } @@ -4433,7 +4443,7 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt) const ret = int(QStyleHelper::dpiScaled(13, opt)); break; case PM_MessageBoxIconSize: -#ifdef Q_OS_MAC +#ifdef Q_OS_APPLE if (QGuiApplication::desktopSettingsAware()) { ret = 64; // No DPI scaling, it's handled elsewhere. } else @@ -4474,7 +4484,6 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt) const QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &csz) const { - Q_D(const QCommonStyle); QSize sz(!csz.isEmpty() ? csz : QSize(0,0)); switch (ct) { @@ -4607,8 +4616,10 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, c sz = QSize(1 + 3 * (buttonSize + 1), buttonSize); } break; +#if QT_CONFIG(quick_itemview) case CT_ItemViewItem: if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { + Q_D(const QCommonStyle); QRect decorationRect, displayRect, checkRect; d->viewItemLayout(vopt, &checkRect, &decorationRect, &displayRect, true); sz = (decorationRect|displayRect|checkRect).size(); @@ -4616,6 +4627,7 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, c sz.rheight() += 2; // Prevent icons from overlapping. } break; +#endif // QT_CONFIG(quick_itemview) case CT_SpinBox: if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) { // Add button + frame widths @@ -4973,9 +4985,11 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, QStyleHintRet case SH_Splitter_OpaqueResize: ret = true; break; +#if QT_CONFIG(quick_itemview) case SH_ItemView_ScrollMode: ret = QStyleOptionViewItem::ScrollPerItem; break; +#endif // QT_CONFIG(quick_itemview) case SH_TitleBar_ShowToolTipsOnButtons: ret = true; break; @@ -5228,8 +5242,8 @@ QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *opti case SP_ToolBarHorizontalExtensionButton: if (rtl) { QImage im(tb_extension_arrow_h_xpm); - im = im.convertToFormat(QImage::Format_ARGB32).mirrored(true, false); - return QPixmap::fromImage(im); + im = std::move(im).convertToFormat(QImage::Format_ARGB32).mirrored(true, false); + return QPixmap::fromImage(std::move(im)); } return cachedPixmapFromXPM(tb_extension_arrow_h_xpm); case SP_ToolBarVerticalExtensionButton: @@ -5648,7 +5662,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption if (!icon.isNull()) return icon; -#if defined(Q_OS_MAC) +#if defined(Q_OS_MACOS) if (QGuiApplication::desktopSettingsAware()) { switch (standardIcon) { case SP_DirIcon: { @@ -5716,7 +5730,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption break; } } // if (QGuiApplication::desktopSettingsAware()) -#endif // Q_OS_MAC +#endif // Q_OS_MACOS switch (standardIcon) { #ifndef QT_NO_IMAGEFORMAT_PNG @@ -6024,7 +6038,7 @@ QPixmap QCommonStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &p } } - return QPixmap::fromImage(im); + return QPixmap::fromImage(std::move(im)); } case QIcon::Selected: { QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); @@ -6034,7 +6048,7 @@ QPixmap QCommonStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &p painter.setCompositionMode(QPainter::CompositionMode_SourceAtop); painter.fillRect(0, 0, img.width(), img.height(), color); painter.end(); - return QPixmap::fromImage(img); } + return QPixmap::fromImage(std::move(img)); } case QIcon::Active: return pixmap; default: diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle_p.h b/src/quicknativestyle/qstyle/qquickcommonstyle_p.h index 83ed85e51d..b597e478cf 100644 --- a/src/quicknativestyle/qstyle/qquickcommonstyle_p.h +++ b/src/quicknativestyle/qstyle/qquickcommonstyle_p.h @@ -30,15 +30,18 @@ class QCommonStylePrivate : public QStylePrivate Q_DECLARE_PUBLIC(QCommonStyle) public: +#if QT_CONFIG(quick_itemview) ~QCommonStylePrivate() { delete cachedOption; } +#endif // QT_CONFIG(quick_itemview) QString calculateElidedText(const QString &text, const QTextOption &textOption, const QFont &font, const QRect &textRect, const Qt::Alignment valign, Qt::TextElideMode textElideMode, int flags, bool lastVisibleLineShouldBeElided, QPointF *paintStartPosition) const; +#if QT_CONFIG(quick_itemview) void viewItemDrawText(QPainter *p, const QStyleOptionViewItem *option, const QRect &rect) const; void viewItemLayout(const QStyleOptionViewItem *opt, QRect *checkRect, QRect *pixmapRect, QRect *textRect, bool sizehint) const; @@ -62,6 +65,7 @@ public: && option.font == cachedOption->font && option.viewItemPosition == cachedOption->viewItemPosition; } +#endif // QT_CONFIG(quick_itemview) QString toolButtonElideText(const QStyleOptionToolButton *toolbutton, const QRect &textRect, int flags) const; diff --git a/src/quicknativestyle/qstyle/qquickstylehelper.cpp b/src/quicknativestyle/qstyle/qquickstylehelper.cpp index dab6b041d8..6b73a5fcf3 100644 --- a/src/quicknativestyle/qstyle/qquickstylehelper.cpp +++ b/src/quicknativestyle/qstyle/qquickstylehelper.cpp @@ -121,14 +121,13 @@ static QPointF calcRadialPos(const QStyleOptionSlider *dial, qreal offset) const int r = qMin(width, height) / 2; const int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition); qreal a = 0; + qreal startAngle = (90. - dial->startAngle) * Q_PI / 180.; + qreal spanAngle = (dial->endAngle - dial->startAngle) * Q_PI / 180.; if (dial->maximum == dial->minimum) a = Q_PI / 2; - else if (dial->dialWrapping) - a = Q_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Q_PI - / (dial->maximum - dial->minimum); else - a = (Q_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * Q_PI - / (dial->maximum - dial->minimum)) / 6; + a = (startAngle - (currentSliderPosition - dial->minimum) * spanAngle + / (dial->maximum - dial->minimum)); qreal xc = width / 2.0; qreal yc = height / 2.0; qreal len = r - QStyleHelper::calcBigLineSize(r) - 3; diff --git a/src/quicknativestyle/qstyle/qquickstyleoption.cpp b/src/quicknativestyle/qstyle/qquickstyleoption.cpp index c3f5df860a..83afa8e399 100644 --- a/src/quicknativestyle/qstyle/qquickstyleoption.cpp +++ b/src/quicknativestyle/qstyle/qquickstyleoption.cpp @@ -385,6 +385,7 @@ QStyleOptionTitleBar::QStyleOptionTitleBar(int versionIn) { } +#if QT_CONFIG(quick_itemview) /*! Constructs a QStyleOptionViewItem, initializing the members variables to their default values. @@ -406,6 +407,7 @@ QStyleOptionViewItem::QStyleOptionViewItem(int versionIn) checkState(Qt::Unchecked), viewItemPosition(QStyleOptionViewItem::Invalid) { } +#endif // QT_CONFIG(quick_itemview) /*! Constructs a QStyleOptionTabWidgetFrame, initializing the members diff --git a/src/quicknativestyle/qstyle/qquickstyleoption.h b/src/quicknativestyle/qstyle/qquickstyleoption.h index e7770cc277..ed430baaca 100644 --- a/src/quicknativestyle/qstyle/qquickstyleoption.h +++ b/src/quicknativestyle/qstyle/qquickstyleoption.h @@ -9,11 +9,15 @@ #include <QtCore/qlocale.h> #include <QtCore/qvariant.h> #include <QtCore/qdebug.h> -#include <QtCore/qabstractitemmodel.h> #include <QtGui/qicon.h> #include <QtGui/qfontmetrics.h> +#include <QtQuick/private/qtquick-config_p.h> +#if QT_CONFIG(quick_itemview) +#include <QtCore/qabstractitemmodel.h> +#endif + QT_BEGIN_NAMESPACE class QQuickItem; @@ -35,7 +39,6 @@ public: SO_CustomBase = 0xf00, SO_ComplexCustomBase = 0xf000000 }; - Q_ENUMS(OptionType) enum StyleOptionType { Type = SO_Default }; enum StyleOptionVersion { Version = 1 }; @@ -376,6 +379,7 @@ protected: Q_DECL_DEPRECATED typedef QStyleOptionDockWidget QStyleOptionDockWidgetV2; +#if QT_CONFIG(quick_itemview) class QStyleOptionViewItem : public QStyleOption { public: @@ -429,6 +433,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QStyleOptionViewItem::ViewItemFeatures) Q_DECL_DEPRECATED typedef QStyleOptionViewItem QStyleOptionViewItemV2; Q_DECL_DEPRECATED typedef QStyleOptionViewItem QStyleOptionViewItemV3; Q_DECL_DEPRECATED typedef QStyleOptionViewItem QStyleOptionViewItemV4; +#endif // QT_CONFIG(quick_itemview) class QStyleOptionToolBox : public QStyleOption { @@ -514,6 +519,8 @@ public: int pageStep; qreal notchTarget; bool dialWrapping; + qreal startAngle; + qreal endAngle; QStyleOptionSlider(); QStyleOptionSlider(const QStyleOptionSlider &other) : QStyleOptionComplex(Version, Type) { *this = other; } diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp index 73b2692241..64528c8fb7 100644 --- a/src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp +++ b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp @@ -2292,7 +2292,7 @@ void QWindowsStyle::refreshPalette() QPalette pal; using QWindowsApplication = QNativeInterface::Private::QWindowsApplication; if (auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration())) - nativeWindowsApp->lightSystemPalette(pal); + nativeWindowsApp->populateLightSystemPalette(pal); QQuickTheme::instance()->setPalette(QQuickTheme::System, pal); } diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp index 4a729b339f..a6b8807ed0 100644 --- a/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp +++ b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp @@ -760,7 +760,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa #ifdef DEBUG_XP_STYLE char buf[25]; - ::sprintf(buf, "+ Pixmap(%3d, %3d) ]", w, h); + ::snprintf(buf, sizeof(buf), "+ Pixmap(%3d, %3d) ]", w, h); printf("---[ CACHED %s--------> Name(%-10s) Part(%d) State(%d)\n", haveCachedPixmap ? buf : "]-------------------", qPrintable(themeData.name), themeData.partId, themeData.stateId); @@ -3879,22 +3879,24 @@ void QWindowsXPStylePrivate::dumpNativeDIB(int w, int h) static int pCount = 0; DWORD *bufPix = (DWORD*)bufferPixels; - char *bufferDump = new char[bufferH * bufferW * 16]; + const unsigned int bufferSize = bufferH * bufferW * 16; + char *bufferDump = new char[bufferSize]; + char *bufferEndAdress = bufferDump + bufferSize; char *bufferPos = bufferDump; memset(bufferDump, 0, sizeof(bufferDump)); - bufferPos += sprintf(bufferPos, "const int pixelBufferW%d = %d;\n", pCount, w); - bufferPos += sprintf(bufferPos, "const int pixelBufferH%d = %d;\n", pCount, h); - bufferPos += sprintf(bufferPos, "const unsigned DWORD pixelBuffer%d[] = {", pCount); + bufferPos += snprintf(bufferPos, bufferEndAdress - bufferPos, "const int pixelBufferW%d = %d;\n", pCount, w); + bufferPos += snprintf(bufferPos, bufferEndAdress - bufferPos, "const int pixelBufferH%d = %d;\n", pCount, h); + bufferPos += snprintf(bufferPos, bufferEndAdress - bufferPos, "const unsigned DWORD pixelBuffer%d[] = {", pCount); for (int iy = 0; iy < h; ++iy) { - bufferPos += sprintf(bufferPos, "\n "); + bufferPos += snprintf(bufferPos, bufferEndAdress - bufferPos, "\n "); bufPix = (DWORD*)(bufferPixels + (iy * bufferW * 4)); for (int ix = 0; ix < w; ++ix) { - bufferPos += sprintf(bufferPos, "0x%08x, ", *bufPix); + bufferPos += snprintf(bufferPos, bufferEndAdress - bufferPos, "0x%08x, ", *bufPix); ++bufPix; } } - bufferPos += sprintf(bufferPos, "\n};\n\n"); + bufferPos += snprintf(bufferPos, bufferEndAdress - bufferPos, "\n};\n\n"); printf(bufferDump); delete[] bufferDump; diff --git a/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp b/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp index e0b0e77bf3..f1ff18c74f 100644 --- a/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp +++ b/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp @@ -13,10 +13,11 @@ #include "qquickcommonstyle.h" #if defined(Q_OS_MACOS) -#include "qquickmacstyle_mac_p.h" #include "qquickmacfocusframe.h" +#include "qquickmacstyle_mac_p.h" #elif defined(Q_OS_WINDOWS) -# include "qquickwindowsxpstyle_p.h" +#include "qquickwindowsfocusframe.h" +#include "qquickwindowsxpstyle_p.h" #endif QT_BEGIN_NAMESPACE @@ -39,8 +40,8 @@ public: void initializeTheme(QQuickTheme *theme) override; QString name() const override; -#if defined(Q_OS_MACOS) - QScopedPointer<QQuickMacFocusFrame> m_focusFrame; +#if defined(Q_OS_MACOS) || defined (Q_OS_WIN) + QScopedPointer<QQuickFocusFrame> m_focusFrame; #endif }; @@ -111,7 +112,7 @@ void QtQuickControls2NativeStylePlugin::initializeEngine(QQmlEngine *engine, con style = new QMacStyle; #elif defined(Q_OS_WINDOWS) style = new QWindowsXPStyle; - if (QGuiApplication::styleHints()->appearance() == Qt::Appearance::Dark) + if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) qobject_cast<QWindowsStyle *>(style)->refreshPalette(); #else style = new QCommonStyle; @@ -121,6 +122,8 @@ void QtQuickControls2NativeStylePlugin::initializeEngine(QQmlEngine *engine, con #if defined(Q_OS_MACOS) m_focusFrame.reset(new QQuickMacFocusFrame()); +#elif defined(Q_OS_WIN) + m_focusFrame.reset(new QQuickWindowsFocusFrame()); #endif qAddPostRoutine(deleteQStyle); diff --git a/src/quicknativestyle/util/FocusFrame.qml b/src/quicknativestyle/util/MacFocusFrame.qml index eebee62c31..c281ff9b53 100644 --- a/src/quicknativestyle/util/FocusFrame.qml +++ b/src/quicknativestyle/util/MacFocusFrame.qml @@ -52,7 +52,7 @@ Item { y: targetItem ? targetItem.y + topOffset - frameSize - root.y : 0 width: targetItem ? targetItem.width - leftOffset - rightOffset + (frameSize * 2) : 0 height: targetItem ? targetItem.height - topOffset - bottomOffset + (frameSize * 2) : 0 - radius: frameRadius + radius: frameRadius + frameSize visible: targetItem && targetItem.visible color: "transparent" @@ -67,7 +67,7 @@ Item { property: "frameSize" duration: 300 from: 15 - to: 2.5 + to: 3 easing.type: Easing.OutCubic } NumberAnimation { diff --git a/src/quicknativestyle/util/WindowsFocusFrame.qml b/src/quicknativestyle/util/WindowsFocusFrame.qml new file mode 100644 index 0000000000..0d23dacf1f --- /dev/null +++ b/src/quicknativestyle/util/WindowsFocusFrame.qml @@ -0,0 +1,58 @@ +// 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 + +Item { + id: root + + // It's important that this item has a zero size. Otherwise, if the parent of the + // targetItem is e.g a layout, we will change the layout if we parent this item inside it. + width: 0 + height: 0 + // Stack on top of all siblings of the targetItem + z: 100 + + function moveToItem(item, margins, radius) { + if (!item) { + targetItem = null; + parent = null; + visible = false; + return; + } + visible = true + parent = item.parent + targetItem = item + leftOffset = margins.left + rightOffset = margins.right + topOffset = margins.top + bottomOffset = margins.bottom + frameRadius = radius + } + + property Item targetItem + property real leftOffset: 0 + property real rightOffset: 0 + property real topOffset: 0 + property real bottomOffset: 0 + property real frameOpacity: 0 + property real frameSize: 0 + property real frameRadius: 0 + + Canvas { + x: targetItem ? targetItem.x + leftOffset - frameSize - root.x : 0 + y: targetItem ? targetItem.y + topOffset - frameSize - root.y : 0 + width: targetItem ? targetItem.width - leftOffset - rightOffset + (frameSize * 2) : 0 + height: targetItem ? targetItem.height - topOffset - bottomOffset + (frameSize * 2) : 0 + visible: targetItem && targetItem.visible + + onPaint: { + let context = getContext("2d") + context.strokeStyle = Qt.rgba(0, 0, 0, 1) + context.setLineDash([1, 1]) + context.beginPath() + context.roundedRect(0.5, 0.5, width - 1, height - 1, root.frameRadius, root.frameRadius) + context.stroke() + } + } +} diff --git a/src/quicknativestyle/util/qquickfocusframe.cpp b/src/quicknativestyle/util/qquickfocusframe.cpp new file mode 100644 index 0000000000..bf1ee5a3ea --- /dev/null +++ b/src/quicknativestyle/util/qquickfocusframe.cpp @@ -0,0 +1,118 @@ +// 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 + +#include "qquickfocusframe.h" + +#include <QtCore/qmetaobject.h> + +#include <QtGui/qguiapplication.h> + +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlcomponent.h> + +#include <QtQuick/qquickitem.h> + +#include "items/qquickstyleitem.h" + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcFocusFrame, "qt.quick.controls.focusframe") + +QQuickFocusFrameDescription QQuickFocusFrameDescription::Invalid = { nullptr, QQuickStyleMargins(), 0 }; +QScopedPointer<QQuickItem> QQuickFocusFrame::m_focusFrame; + +QQuickFocusFrame::QQuickFocusFrame() +{ + connect(qGuiApp, &QGuiApplication::focusObjectChanged, this, [this]{ + if (auto item = qobject_cast<QQuickItem *>(qGuiApp->focusObject())) + moveToItem(item); + }); +} + +void QQuickFocusFrame::moveToItem(QQuickItem *item) +{ + if (!m_focusFrame) { + const auto context = QQmlEngine::contextForObject(item); + // In certain cases like QQuickWebEngineView, the item + // gets focus even though it has no QQmlEngine associated with its context. + // We need the engine for creating the focus frame component. + if (!context || !context->engine()) + return; + m_focusFrame.reset(createFocusFrame(context)); + if (!m_focusFrame) { + qWarning() << "Failed to create FocusFrame"; + return; + } + } + + const QQuickFocusFrameDescription &config = getDescriptionForItem(item); + QMetaObject::invokeMethod(m_focusFrame.data(), "moveToItem", + Q_ARG(QVariant, QVariant::fromValue(config.target)), + Q_ARG(QVariant, QVariant::fromValue(config.margins)), + Q_ARG(QVariant, QVariant::fromValue(config.radius))); +} + +QQuickFocusFrameDescription QQuickFocusFrame::getDescriptionForItem(QQuickItem *focusItem) const +{ + qCDebug(lcFocusFrame) << "new focusobject:" << focusItem; + const auto parentItem = focusItem->parentItem(); + if (!parentItem) + return QQuickFocusFrameDescription::Invalid; + + // The item that gets active focus can be a child of the control (e.g + // editable ComboBox). In that case, resolve the actual control first. + const auto proxy = focusItem->property("__focusFrameControl").value<QQuickItem *>(); + const auto control = proxy ? proxy : focusItem; + auto target = control->property("__focusFrameTarget").value<QQuickItem *>(); + qCDebug(lcFocusFrame) << "target:" << target; + qCDebug(lcFocusFrame) << "control:" << control; + + if (!target) { + // __focusFrameTarget points to the item in the control that should + // get the focus frame. This is usually the control itself, but can + // sometimes be a child (CheckBox). We anyway require + // this property to be set if we are to show the focus frame around + // the control in the first place. So for controls that don't want + // a frame (ProgressBar), we simply skip setting it. + // Also, we should never show a focus frame around custom controls. + // None of the built-in styles do that, so to be consistent, we + // shouldn't either. Besides, drawing a focus frame around an unknown + // item without any way to turn it off can easily be unwanted. A better + // way for custom controls to get a native focus frame is for us to offer + // a FocusFrame control (QTBUG-86818). + return QQuickFocusFrameDescription::Invalid; + } + + // If the control gives us a QQuickStyleItem, we use that to configure the focus frame. + // By default we assume that the background delegate is a QQuickStyleItem, but the + // control can override this by setting __focusFrameStyleItem. + const auto styleItemProperty = control->property("__focusFrameStyleItem"); + auto item = styleItemProperty.value<QQuickItem *>(); + if (!item) { + const auto styleItemProperty = control->property("background"); + item = styleItemProperty.value<QQuickItem *>(); + } + qCDebug(lcFocusFrame) << "styleItem:" << item; + if (!item) + return QQuickFocusFrameDescription::Invalid; + if (QQuickStyleItem *styleItem = qobject_cast<QQuickStyleItem *>(item)) + return { target, QQuickStyleMargins(styleItem->layoutMargins()), styleItem->focusFrameRadius() }; + + // Some controls don't have a QQuickStyleItem. But if the __focusFrameStyleItem + // has a "__focusFrameRadius" property set, we show a default focus frame using the specified radius instead. + const QVariant focusFrameRadiusVariant = item->property("__focusFrameRadius"); + if (focusFrameRadiusVariant.isValid()) { + qCDebug(lcFocusFrame) << "'focusFrameRadius' property found, showing a default focus frame"; + const QStyleOption opt; + const qreal radius = qMax(0.0, focusFrameRadiusVariant.toReal()); + return { target, QQuickStyleMargins(), radius }; + } + + // The application has set a custom delegate on the control. In that + // case, it's the delegates responsibility to draw a focus frame. + qCDebug(lcFocusFrame) << "custom delegates in use, skip showing focus frame"; + return QQuickFocusFrameDescription::Invalid; +} + +QT_END_NAMESPACE diff --git a/src/quicknativestyle/util/qquickfocusframe.h b/src/quicknativestyle/util/qquickfocusframe.h new file mode 100644 index 0000000000..2121d6bdc5 --- /dev/null +++ b/src/quicknativestyle/util/qquickfocusframe.h @@ -0,0 +1,39 @@ +// 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 + +#ifndef QQUICKFOCUSFRAME_H +#define QQUICKFOCUSFRAME_H + +#include <QtQuick/qquickitem.h> +#include "qquickstyleitem.h" + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcFocusFrame) + +struct QQuickFocusFrameDescription { + QQuickItem *target; + QQuickStyleMargins margins; + const qreal radius = 3; + bool isValid() const { return target != nullptr; } + static QQuickFocusFrameDescription Invalid; +}; + +class QQuickFocusFrame : public QObject +{ + Q_OBJECT + +public: + QQuickFocusFrame(); + +private: + static QScopedPointer<QQuickItem> m_focusFrame; + + virtual QQuickItem *createFocusFrame(QQmlContext *context) = 0; + void moveToItem(QQuickItem *item); + QQuickFocusFrameDescription getDescriptionForItem(QQuickItem *focusItem) const; +}; + +QT_END_NAMESPACE + +#endif // QQUICKFOCUSFRAME_H diff --git a/src/quicknativestyle/util/qquickmacfocusframe.h b/src/quicknativestyle/util/qquickmacfocusframe.h index 88858c7688..e52cc9a300 100644 --- a/src/quicknativestyle/util/qquickmacfocusframe.h +++ b/src/quicknativestyle/util/qquickmacfocusframe.h @@ -1,38 +1,22 @@ -// Copyright (C) 2020 The Qt Company Ltd. +// 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 #ifndef QQUICKMACFOCUSFRAME_H #define QQUICKMACFOCUSFRAME_H -#include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquicktextedit_p.h> -#include "qquickstyleitem.h" +#include "qquickfocusframe.h" QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(lcFocusFrame) - -struct QQuickFocusFrameDescription { - QQuickItem *target; - QQuickStyleMargins margins; - const qreal radius = 3; - bool isValid() const { return target != nullptr; } - static QQuickFocusFrameDescription Invalid; -}; - -class QQuickMacFocusFrame : public QObject +class QQuickMacFocusFrame : public QQuickFocusFrame { Q_OBJECT public: - QQuickMacFocusFrame(); + QQuickMacFocusFrame() = default; private: - static QScopedPointer<QQuickItem> m_focusFrame; - - void createFocusFrame(QQmlContext *context); - void moveToItem(QQuickItem *item); - QQuickFocusFrameDescription getDescriptionForItem(QQuickItem *focusItem) const; + virtual QQuickItem *createFocusFrame(QQmlContext *context) override; }; QT_END_NAMESPACE diff --git a/src/quicknativestyle/util/qquickmacfocusframe.mm b/src/quicknativestyle/util/qquickmacfocusframe.mm index 8ebaf223be..c47d3e1b0a 100644 --- a/src/quicknativestyle/util/qquickmacfocusframe.mm +++ b/src/quicknativestyle/util/qquickmacfocusframe.mm @@ -1,141 +1,31 @@ -// Copyright (C) 2020 The Qt Company Ltd. +// 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 #include "qquickmacfocusframe.h" #include <AppKit/AppKit.h> -#include <QtCore/qmetaobject.h> - #include <QtGui/qguiapplication.h> #include <QtGui/private/qcoregraphics_p.h> -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlcontext.h> #include <QtQml/qqmlcomponent.h> -#include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquicktextinput_p.h> -#include <QtQuick/private/qquicktextedit_p.h> -#include <QtQuick/private/qquickflickable_p.h> - -#include <QtQuickTemplates2/private/qquickframe_p.h> -#include <QtQuickTemplates2/private/qquickbutton_p.h> -#include <QtQuickTemplates2/private/qquickscrollview_p.h> -#include <QtQuickTemplates2/private/qquickslider_p.h> -#include <QtQuickTemplates2/private/qquickcombobox_p.h> -#include <QtQuickTemplates2/private/qquickcheckbox_p.h> -#include <QtQuickTemplates2/private/qquickradiobutton_p.h> -#include <QtQuickTemplates2/private/qquickspinbox_p.h> -#include <QtQuickTemplates2/private/qquicktextfield_p.h> -#include <QtQuickTemplates2/private/qquicktextarea_p.h> - -#include "items/qquickstyleitem.h" -#include "qquicknativestyle.h" - QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcFocusFrame, "qt.quick.controls.focusframe") - -QQuickFocusFrameDescription QQuickFocusFrameDescription::Invalid = { nullptr, QQuickStyleMargins(), 0 }; -QScopedPointer<QQuickItem> QQuickMacFocusFrame::m_focusFrame; - -QQuickMacFocusFrame::QQuickMacFocusFrame() -{ - connect(qGuiApp, &QGuiApplication::focusObjectChanged, [=]{ - if (auto item = qobject_cast<QQuickItem *>(qGuiApp->focusObject())) - moveToItem(item); - }); -} - -void QQuickMacFocusFrame::moveToItem(QQuickItem *item) -{ - if (!m_focusFrame) { - const auto context = QQmlEngine::contextForObject(item); - if (!context) - return; - createFocusFrame(context); - } - - const QQuickFocusFrameDescription &config = getDescriptionForItem(item); - QMetaObject::invokeMethod(m_focusFrame.data(), "moveToItem", - Q_ARG(QVariant, QVariant::fromValue(config.target)), - Q_ARG(QVariant, QVariant::fromValue(config.margins)), - Q_ARG(QVariant, QVariant::fromValue(config.radius))); -} - -void QQuickMacFocusFrame::createFocusFrame(QQmlContext *context) +QQuickItem *QQuickMacFocusFrame::createFocusFrame(QQmlContext *context) { QQmlComponent component( context->engine(), QUrl(QStringLiteral( - "qrc:/qt-project.org/imports/QtQuick/NativeStyle/util/FocusFrame.qml"))); - m_focusFrame.reset(qobject_cast<QQuickItem *>(component.create())); + "qrc:/qt-project.org/imports/QtQuick/NativeStyle/util/MacFocusFrame.qml"))); + auto frame = qobject_cast<QQuickItem *>(component.create()); + if (!frame) + return nullptr; auto indicatorColor = qt_mac_toQColor(NSColor.keyboardFocusIndicatorColor.CGColor); indicatorColor.setAlpha(255); - m_focusFrame->setProperty("systemFrameColor", indicatorColor); -} - -QQuickFocusFrameDescription QQuickMacFocusFrame::getDescriptionForItem(QQuickItem *focusItem) const -{ - qCDebug(lcFocusFrame) << "new focusobject:" << focusItem; - const auto parentItem = focusItem->parentItem(); - if (!parentItem) - return QQuickFocusFrameDescription::Invalid; - - // The item that gets active focus can be a child of the control (e.g - // editable ComboBox). In that case, resolve the actual control first. - const auto proxy = focusItem->property("__focusFrameControl").value<QQuickItem *>(); - const auto control = proxy ? proxy : focusItem; - auto target = control->property("__focusFrameTarget").value<QQuickItem *>(); - qCDebug(lcFocusFrame) << "target:" << target; - qCDebug(lcFocusFrame) << "control:" << control; - - if (!target) { - // __focusFrameTarget points to the item in the control that should - // get the focus frame. This is usually the control itself, but can - // sometimes be a child (CheckBox). We anyway require - // this property to be set if we are to show the focus frame around - // the control in the first place. So for controls that don't want - // a frame (ProgressBar), we simply skip setting it. - // Also, we should never show a focus frame around custom controls. - // None of the built-in styles do that, so to be consistent, we - // shouldn't either. Besides, drawing a focus frame around an unknown - // item without any way to turn it off can easily be unwanted. A better - // way for custom controls to get a native focus frame is for us to offer - // a FocusFrame control (QTBUG-86818). - return QQuickFocusFrameDescription::Invalid; - } - - // If the control gives us a QQuickStyleItem, we use that to configure the focus frame. - // By default we assume that the background delegate is a QQuickStyleItem, but the - // control can override this by setting __focusFrameStyleItem. - const auto styleItemProperty = control->property("__focusFrameStyleItem"); - auto item = styleItemProperty.value<QQuickItem *>(); - if (!item) { - const auto styleItemProperty = control->property("background"); - item = styleItemProperty.value<QQuickItem *>(); - } - qCDebug(lcFocusFrame) << "styleItem:" << item; - if (!item) - return QQuickFocusFrameDescription::Invalid; - if (QQuickStyleItem *styleItem = qobject_cast<QQuickStyleItem *>(item)) - return { target, QQuickStyleMargins(styleItem->layoutMargins()), styleItem->focusFrameRadius() }; - - // Some controls don't have a QQuickStyleItem. But if the __focusFrameStyleItem - // has a "__isDefaultDelegate" property set, we show a default focus frame instead. - if (item->property("__isDefaultDelegate").toBool() == true) { - qCDebug(lcFocusFrame) << "'__isDefaultDelegate' property found, showing a default focus frame"; - const QStyleOption opt; - const qreal radius = QQuickNativeStyle::style()->pixelMetric(QStyle::PM_TextFieldFocusFrameRadius, &opt); - return { target, QQuickStyleMargins(), radius }; - } - - // The application has set a custom delegate on the control. In that - // case, it's the delegates responsibility to draw a focus frame. - qCDebug(lcFocusFrame) << "custom delegates in use, skip showing focus frame"; - return QQuickFocusFrameDescription::Invalid; + frame->setProperty("systemFrameColor", indicatorColor); + return frame; } QT_END_NAMESPACE diff --git a/src/quicknativestyle/util/qquickwindowsfocusframe.cpp b/src/quicknativestyle/util/qquickwindowsfocusframe.cpp new file mode 100644 index 0000000000..a92af42e21 --- /dev/null +++ b/src/quicknativestyle/util/qquickwindowsfocusframe.cpp @@ -0,0 +1,17 @@ +// 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 + +#include "qquickwindowsfocusframe.h" + +#include <QtQml/qqmlcomponent.h> + +QT_BEGIN_NAMESPACE + +QQuickItem *QQuickWindowsFocusFrame::createFocusFrame(QQmlContext *context) +{ + QQmlComponent component(context->engine(), + QUrl(QStringLiteral("qrc:/qt-project.org/imports/QtQuick/NativeStyle/util/WindowsFocusFrame.qml"))); + return qobject_cast<QQuickItem *>(component.create()); +} + +QT_END_NAMESPACE diff --git a/src/quicknativestyle/util/qquickwindowsfocusframe.h b/src/quicknativestyle/util/qquickwindowsfocusframe.h new file mode 100644 index 0000000000..5bd60a1343 --- /dev/null +++ b/src/quicknativestyle/util/qquickwindowsfocusframe.h @@ -0,0 +1,24 @@ +// 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 + +#ifndef QQUICKWINDOWSFOCUSFRAME_H +#define QQUICKWINDOWSFOCUSFRAME_H + +#include "qquickfocusframe.h" + +QT_BEGIN_NAMESPACE + +class QQuickWindowsFocusFrame : public QQuickFocusFrame +{ + Q_OBJECT + +public: + QQuickWindowsFocusFrame() = default; + +private: + virtual QQuickItem *createFocusFrame(QQmlContext *context) override; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWINDOWSFOCUSFRAME_H |