aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/imports/controls/macos/Button.qml2
-rw-r--r--src/imports/controls/macos/CheckBox.qml2
-rw-r--r--src/imports/controls/macos/ComboBox.qml24
-rw-r--r--src/imports/controls/macos/RadioButton.qml2
-rw-r--r--src/imports/controls/macos/Slider.qml2
-rw-r--r--src/imports/controls/macos/SpinBox.qml4
-rw-r--r--src/imports/controls/macos/TextArea.qml17
-rw-r--r--src/imports/controls/macos/TextField.qml2
-rw-r--r--src/imports/nativestyle/CMakeLists.txt16
-rw-r--r--src/imports/nativestyle/nativestyle.pro1
-rw-r--r--src/imports/nativestyle/qtquickcontrols2nativestyleplugin.cpp9
-rw-r--r--src/imports/nativestyle/util/FocusFrame.qml118
-rw-r--r--src/imports/nativestyle/util/qquickmacfocusframe.h73
-rw-r--r--src/imports/nativestyle/util/qquickmacfocusframe.mm179
-rw-r--r--src/imports/nativestyle/util/util.pri11
15 files changed, 462 insertions, 0 deletions
diff --git a/src/imports/controls/macos/Button.qml b/src/imports/controls/macos/Button.qml
index e3fe856d..58658c52 100644
--- a/src/imports/controls/macos/Button.qml
+++ b/src/imports/controls/macos/Button.qml
@@ -38,4 +38,6 @@ import QtQuick
import QtQuick.NativeStyle as NativeStyle
NativeStyle.DefaultButton {
+ id: control
+ readonly property Item __focusFrameTarget: control
}
diff --git a/src/imports/controls/macos/CheckBox.qml b/src/imports/controls/macos/CheckBox.qml
index d1a56fee..23ad4426 100644
--- a/src/imports/controls/macos/CheckBox.qml
+++ b/src/imports/controls/macos/CheckBox.qml
@@ -38,4 +38,6 @@ import QtQuick
import QtQuick.NativeStyle as NativeStyle
NativeStyle.DefaultCheckBox {
+ readonly property Item __focusFrameTarget: indicator
+ readonly property Item __focusFrameStyleItem: indicator
}
diff --git a/src/imports/controls/macos/ComboBox.qml b/src/imports/controls/macos/ComboBox.qml
index 3891594b..53baabf8 100644
--- a/src/imports/controls/macos/ComboBox.qml
+++ b/src/imports/controls/macos/ComboBox.qml
@@ -35,7 +35,31 @@
****************************************************************************/
import QtQuick
+import QtQuick.Templates as T
import QtQuick.NativeStyle as NativeStyle
NativeStyle.DefaultComboBox {
+ id: control
+ readonly property Item __focusFrameTarget: control
+
+ contentItem: T.TextField {
+ implicitWidth: contentWidth
+ implicitHeight: contentHeight
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.editable ? control.palette.text : control.palette.buttonText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Text.AlignVCenter
+
+ readonly property Item __focusFrameControl: control
+ }
}
diff --git a/src/imports/controls/macos/RadioButton.qml b/src/imports/controls/macos/RadioButton.qml
index 82b85698..c9cdf985 100644
--- a/src/imports/controls/macos/RadioButton.qml
+++ b/src/imports/controls/macos/RadioButton.qml
@@ -38,4 +38,6 @@ import QtQuick
import QtQuick.NativeStyle as NativeStyle
NativeStyle.DefaultRadioButton {
+ readonly property Item __focusFrameTarget: indicator
+ readonly property Item __focusFrameStyleItem: indicator
}
diff --git a/src/imports/controls/macos/Slider.qml b/src/imports/controls/macos/Slider.qml
index ab72fcaa..e8e0e036 100644
--- a/src/imports/controls/macos/Slider.qml
+++ b/src/imports/controls/macos/Slider.qml
@@ -38,4 +38,6 @@ import QtQuick
import QtQuick.NativeStyle as NativeStyle
NativeStyle.DefaultSlider {
+ readonly property Item __focusFrameTarget: handle
+ readonly property Item __focusFrameStyleItem: handle
}
diff --git a/src/imports/controls/macos/SpinBox.qml b/src/imports/controls/macos/SpinBox.qml
index 1eb7fa05..5928d37e 100644
--- a/src/imports/controls/macos/SpinBox.qml
+++ b/src/imports/controls/macos/SpinBox.qml
@@ -62,6 +62,8 @@ T.SpinBox {
rightPadding: (__nativeBackground ? background.contentPadding.right : 0) + rightInset
bottomPadding: __nativeBackground ? background.contentPadding.bottom: 0
+ readonly property Item __focusFrameTarget: contentItem
+
validator: IntValidator {
locale: control.locale.name
bottom: Math.min(control.from, control.to)
@@ -85,6 +87,8 @@ T.SpinBox {
readOnly: !control.editable
validator: control.validator
inputMethodHints: control.inputMethodHints
+
+ readonly property Item __focusFrameControl: control
}
NativeStyle.SpinBox {
diff --git a/src/imports/controls/macos/TextArea.qml b/src/imports/controls/macos/TextArea.qml
index f6b88303..98884bda 100644
--- a/src/imports/controls/macos/TextArea.qml
+++ b/src/imports/controls/macos/TextArea.qml
@@ -38,4 +38,21 @@ import QtQuick
import QtQuick.NativeStyle as NativeStyle
NativeStyle.DefaultTextArea {
+ id: control
+
+ // If you place a TextArea inside a Frame or Flickable (/ScrollView), and
+ // the TextArea is the only child of the content item, we place the focus
+ // frame around the Flickable/Frame instead.
+ readonly property Item __focusFrameTarget:
+ (parent.parent instanceof Frame || parent.parent instanceof Flickable)
+ && parent.children.length === 1
+ ? parent.parent : control
+
+ background: Rectangle {
+ color: control.palette.light
+ // Since this delegate is a plain Rectangle, we need to tag it to know
+ // that it's still the default one, and not some custom item set by the
+ // application. Only in the former case do we wan't to show a focus frame.
+ readonly property bool __isDefaultDelegate: true
+ }
}
diff --git a/src/imports/controls/macos/TextField.qml b/src/imports/controls/macos/TextField.qml
index bc0e2cb7..f3a748f6 100644
--- a/src/imports/controls/macos/TextField.qml
+++ b/src/imports/controls/macos/TextField.qml
@@ -38,4 +38,6 @@ import QtQuick
import QtQuick.NativeStyle as NativeStyle
NativeStyle.DefaultTextField {
+ id: control
+ readonly property Item __focusFrameTarget: control
}
diff --git a/src/imports/nativestyle/CMakeLists.txt b/src/imports/nativestyle/CMakeLists.txt
index 1b6ce728..d6021e04 100644
--- a/src/imports/nativestyle/CMakeLists.txt
+++ b/src/imports/nativestyle/CMakeLists.txt
@@ -39,6 +39,7 @@ qt_add_qml_module(qtquickcontrols2nativestyleplugin
INCLUDE_DIRECTORIES
items
qstyle
+ util
LIBRARIES
Qt::CorePrivate
Qt::GuiPrivate
@@ -69,12 +70,27 @@ qt_extend_target(qtquickcontrols2nativestyleplugin CONDITION MACOS
SOURCES
qstyle/mac/qquickmacstyle_mac.mm qstyle/mac/qquickmacstyle_mac_p.h
qstyle/mac/qquickmacstyle_mac_p_p.h
+ util/qquickmacfocusframe.h util/qquickmacfocusframe.mm
INCLUDE_DIRECTORIES
qstyle/mac
LIBRARIES
${FWAppKit}
)
+if(MACOS)
+ # Resources:
+ set(qmake_immediate_resource_files
+ "util/FocusFrame.qml"
+ )
+
+ qt_add_resource(qtquickcontrols2nativestyleplugin "qmake_immediate"
+ PREFIX
+ "/"
+ FILES
+ ${qmake_immediate_resource_files}
+ )
+endif()
+
qt_extend_target(qtquickcontrols2nativestyleplugin CONDITION WIN32
SOURCES
qstyle/windows/qquickwindowsstyle.cpp qstyle/windows/qquickwindowsstyle_p.h
diff --git a/src/imports/nativestyle/nativestyle.pro b/src/imports/nativestyle/nativestyle.pro
index b06e5daf..c493080a 100644
--- a/src/imports/nativestyle/nativestyle.pro
+++ b/src/imports/nativestyle/nativestyle.pro
@@ -12,6 +12,7 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
include(items/items.pri)
include(qstyle/qstyle.pri)
include(controls/controls.pri)
+include(util/util.pri)
OTHER_FILES += \
qmldir \
diff --git a/src/imports/nativestyle/qtquickcontrols2nativestyleplugin.cpp b/src/imports/nativestyle/qtquickcontrols2nativestyleplugin.cpp
index ef8bfb9f..cf9b5ccf 100644
--- a/src/imports/nativestyle/qtquickcontrols2nativestyleplugin.cpp
+++ b/src/imports/nativestyle/qtquickcontrols2nativestyleplugin.cpp
@@ -45,6 +45,7 @@
#if defined(Q_OS_MACOS)
#include "qquickmacstyle_mac_p.h"
+#include "qquickmacfocusframe.h"
#elif defined(Q_OS_WINDOWS)
# include "qquickwindowsxpstyle_p.h"
#endif
@@ -64,6 +65,10 @@ public:
void initializeEngine(QQmlEngine *engine, const char *uri) override;
void initializeTheme(QQuickTheme *theme) override;
QString name() const override;
+
+#if defined(Q_OS_MACOS)
+ QScopedPointer<QQuickMacFocusFrame> m_focusFrame;
+#endif
};
static void deleteQStyle()
@@ -132,6 +137,10 @@ void QtQuickControls2NativeStylePlugin::initializeEngine(QQmlEngine *engine, con
}
}
+#if defined(Q_OS_MACOS)
+ m_focusFrame.reset(new QQuickMacFocusFrame());
+#endif
+
qAddPostRoutine(deleteQStyle);
QQuickNativeStyle::setStyle(style);
}
diff --git a/src/imports/nativestyle/util/FocusFrame.qml b/src/imports/nativestyle/util/FocusFrame.qml
new file mode 100644
index 00000000..6bac460d
--- /dev/null
+++ b/src/imports/nativestyle/util/FocusFrame.qml
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+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) {
+ parent = item.parent
+ targetItem = item
+ leftOffset = margins.left
+ rightOffset = margins.right
+ topOffset = margins.top
+ bottomOffset = margins.bottom
+ frameRadius = radius
+ animation.restart()
+ }
+
+ 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
+
+ property point targetItemPos: {
+ if (!targetItem)
+ return Qt.point(0, 0)
+ // Force a reevaluation if
+ // the target item moves
+ targetItem.x
+ targetItem.y
+ mapFromItem(targetItem, Qt.point(0, 0))
+ }
+
+ // systemFrameColor is set to NSColor.keyboardFocusIndicatorColor from cpp
+ property color systemFrameColor
+
+ Rectangle {
+ id: focusFrame
+ z: 10
+ x: targetItemPos.x + leftOffset - frameSize
+ y: targetItemPos.y + topOffset - frameSize
+ width: targetItem ? targetItem.width - leftOffset - rightOffset + (frameSize * 2) : 0
+ height: targetItem ? targetItem.height - topOffset - bottomOffset + (frameSize * 2) : 0
+ radius: frameRadius
+ visible: targetItem
+ color: "transparent"
+
+ border.color: systemFrameColor
+ border.width: frameSize
+ }
+
+ ParallelAnimation {
+ id: animation
+ NumberAnimation {
+ target: root
+ property: "frameSize"
+ duration: 300
+ from: 15
+ to: 2.5
+ easing.type: Easing.OutCubic
+ }
+ NumberAnimation {
+ target: focusFrame
+ property: "opacity"
+ duration: 300
+ from: 0
+ to: 0.55
+ easing.type: Easing.OutCubic
+ }
+ }
+}
diff --git a/src/imports/nativestyle/util/qquickmacfocusframe.h b/src/imports/nativestyle/util/qquickmacfocusframe.h
new file mode 100644
index 00000000..425b2a68
--- /dev/null
+++ b/src/imports/nativestyle/util/qquickmacfocusframe.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMACFOCUSFRAME_H
+#define QQUICKMACFOCUSFRAME_H
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquicktextedit_p.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 QQuickMacFocusFrame : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickMacFocusFrame();
+
+private:
+ static QScopedPointer<QQuickItem> m_focusFrame;
+
+ void createFocusFrame(QQmlContext *context);
+ void moveToItem(QQuickItem *item);
+ QQuickFocusFrameDescription getDescriptionForItem(QQuickItem *focusItem) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKMACFOCUSFRAME_H
diff --git a/src/imports/nativestyle/util/qquickmacfocusframe.mm b/src/imports/nativestyle/util/qquickmacfocusframe.mm
new file mode 100644
index 00000000..87d37366
--- /dev/null
+++ b/src/imports/nativestyle/util/qquickmacfocusframe.mm
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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);
+ if (!config.isValid()) {
+ m_focusFrame->setParentItem(nullptr);
+ m_focusFrame->setVisible(false);
+ return;
+ }
+
+ m_focusFrame->setVisible(true);
+ 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)
+{
+ QQmlComponent component(context->engine(), QUrl(QStringLiteral("qrc:/util/FocusFrame.qml")));
+ m_focusFrame.reset(qobject_cast<QQuickItem *>(component.create()));
+
+ 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;
+ const 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), and other times a grand parent
+ // (a ScrollView that has a TextArea as child). 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 (TextArea). 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;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/nativestyle/util/util.pri b/src/imports/nativestyle/util/util.pri
new file mode 100644
index 00000000..96786eac
--- /dev/null
+++ b/src/imports/nativestyle/util/util.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH += $$PWD
+
+macos {
+ HEADERS += \
+ $$PWD/qquickmacfocusframe.h \
+
+ SOURCES += \
+ $$PWD/qquickmacfocusframe.mm \
+
+ RESOURCES += $$PWD/FocusFrame.qml
+}