QWindowPrivate: Introduce virtual setFocusToTarget

When a window gains focus, the focus will be set to the focusWidget,
if one exists, in the case of QWidgetWindow, and to the window's
contentItem's subFocusItem, in the case of QQuickWindow.
However, we want to be able to customize this as we may want to set
the focus item/widget to the first, last, prev, or next, depending
for example, on the reason the window got focus. Eg.: on a TabKey
we want to focus the next focus object, on a BackTabKey the previous
one, and so on.
To be able to do this, add a virtual method in QWindowPrivate that sets focus to the specified item, and override for QWidgetWindowPrivate.

Task-number: QTBUG-121789
Done-with: axel.spoerl@qt.io
Change-Id: Ib5e17d6ff52c2323a4013c80bf411e92b4c8ce9b
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Doris Verria 2024-02-08 22:10:09 +01:00 committed by Shawn Rutledge
parent f8359084b9
commit 8c44064f62
3 changed files with 54 additions and 1 deletions

View File

@ -76,6 +76,16 @@ public:
void setTransientParent(QWindow *parent);
virtual void clearFocusObject();
enum class FocusTarget {
First,
Last,
Current,
Next,
Prev
};
virtual void setFocusToTarget(QWindowPrivate::FocusTarget) {}
virtual QRectF closestAcceptableGeometry(const QRectF &rect) const;
void setMinOrMaxSize(QSize *oldSizeMember, const QSize &size,

View File

@ -77,6 +77,39 @@ public:
widget->focusWidget()->clearFocus();
}
void setFocusToTarget(QWindowPrivate::FocusTarget target) override
{
Q_Q(QWidgetWindow);
QWidget *widget = q->widget();
if (!widget)
return;
QWidget *newFocusWidget = nullptr;
switch (target) {
case FocusTarget::First:
newFocusWidget = q->getFocusWidget(QWidgetWindow::FirstFocusWidget);
break;
case FocusTarget::Last:
newFocusWidget = q->getFocusWidget(QWidgetWindow::LastFocusWidget);
break;
case FocusTarget::Next: {
QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
newFocusWidget = focusWidget->nextInFocusChain() ? focusWidget->nextInFocusChain() : focusWidget;
break;
}
case FocusTarget::Prev: {
QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
newFocusWidget = focusWidget->previousInFocusChain() ? focusWidget->previousInFocusChain() : focusWidget;
break;
}
default:
break;
}
if (newFocusWidget)
newFocusWidget->setFocus();
}
QRectF closestAcceptableGeometry(const QRectF &rect) const override;
void processSafeAreaMarginsChanged() override

View File

@ -5,6 +5,7 @@
#include "qwidget_p.h"
#include "qwidgetwindow_p.h"
#include <QtGui/qwindow.h>
#include <QtGui/private/qwindow_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <QDebug>
@ -317,8 +318,17 @@ bool QWindowContainer::event(QEvent *e)
break;
case QEvent::FocusIn:
if (d->window->parent()) {
if (QGuiApplication::focusWindow() != d->window)
if (QGuiApplication::focusWindow() != d->window) {
QFocusEvent *event = static_cast<QFocusEvent *>(e);
const auto reason = event->reason();
QWindowPrivate::FocusTarget target = QWindowPrivate::FocusTarget::Current;
if (reason == Qt::TabFocusReason)
target = QWindowPrivate::FocusTarget::First;
else if (reason == Qt::BacktabFocusReason)
target = QWindowPrivate::FocusTarget::Last;
qt_window_private(d->window)->setFocusToTarget(target);
d->window->requestActivate();
}
}
break;
#if QT_CONFIG(draganddrop)