summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qwidget.cpp
diff options
context:
space:
mode:
authorAlessandro Portale <aportale@trolltech.com>2009-09-19 11:37:38 (GMT)
committerAlessandro Portale <aportale@trolltech.com>2009-09-19 11:37:38 (GMT)
commitcd48ed92670a0d086589b202364f38f14e7221c9 (patch)
treea3e9d51e75822a1380699d7cd5fb87ee1522239d /src/gui/kernel/qwidget.cpp
parent3581668cd0ffbe47a05ce7467f8d89b8c9bb6101 (diff)
downloadQt-cd48ed92670a0d086589b202364f38f14e7221c9.zip
Qt-cd48ed92670a0d086589b202364f38f14e7221c9.tar.gz
Qt-cd48ed92670a0d086589b202364f38f14e7221c9.tar.bz2
Making Keypad Navigation more usable
All changes of this commit are #ifdef'ed in QT_KEYPAD_NAVIGATION. Most desktop Qts won't notice any change. Navigating between QWidgets was not alwys a pleasure on keypad devices. This commit fixes the navigation behavior for some widgets, mostly itemviews. Furthermore, it adds a 'directional' navigation mode. Until now, the existing keypad navigation used the tab order do go back and forth between widgets. The new mode is supposed to provide a more intuitive navigation. It is the new default mode on Symbian. Screens (and their resolutions) become bigger, and also low resolution screens can be used in landscape mode. That's why the directional mode was requested. Another popular request was to put some more convenience into QSlider: If a (horizontal) slider has focus and the user presses left/right, the value of the slider may directing change without being selected (edit mode). This commit also adds the manual test 'keypadnavigation'. Reviewed-by: Shane Kearns
Diffstat (limited to 'src/gui/kernel/qwidget.cpp')
-rw-r--r--src/gui/kernel/qwidget.cpp90
1 files changed, 85 insertions, 5 deletions
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 860b98b..4f1ab94 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -410,7 +410,6 @@ void QWidget::setEditFocus(bool on)
QApplication::sendEvent(f, &event);
QApplication::sendEvent(f->style(), &event);
}
- f->repaint(); // Widget might want to repaint a focus indicator
}
#endif
@@ -6449,6 +6448,8 @@ void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw)
This function is called from QDesktopwidget::screen(QPoint) to find the
closest screen for a point.
+ In directional KeypadNavigation, it is called to find the closest
+ widget to the current focus widget center.
*/
int QWidgetPrivate::pointToRect(const QPoint &p, const QRect &r)
{
@@ -7929,10 +7930,21 @@ bool QWidget::event(QEvent *event)
#ifdef QT_KEYPAD_NAVIGATION
if (!k->isAccepted() && QApplication::keypadNavigationEnabled()
&& !(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::ShiftModifier))) {
- if (k->key() == Qt::Key_Up)
- res = focusNextPrevChild(false);
- else if (k->key() == Qt::Key_Down)
- res = focusNextPrevChild(true);
+ if (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder) {
+ if (k->key() == Qt::Key_Up)
+ res = focusNextPrevChild(false);
+ else if (k->key() == Qt::Key_Down)
+ res = focusNextPrevChild(true);
+ } else if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
+ if (k->key() == Qt::Key_Up)
+ res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionNorth);
+ else if (k->key() == Qt::Key_Right)
+ res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionEast);
+ else if (k->key() == Qt::Key_Down)
+ res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionSouth);
+ else if (k->key() == Qt::Key_Left)
+ res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionWest);
+ }
if (res) {
k->accept();
break;
@@ -11373,6 +11385,74 @@ QRect QWidgetPrivate::frameStrut() const
return maybeTopData() ? maybeTopData()->frameStrut : QRect();
}
+#ifdef QT_KEYPAD_NAVIGATION
+/*!
+ \internal
+
+ Changes the focus from the current focusWidget to a widget in
+ the \a direction.
+
+ Returns true, if there was a widget in that direction
+*/
+bool QWidgetPrivate::navigateToDirection(Direction direction)
+{
+ QWidget *targetWidget = widgetInNavigationDirection(direction);
+ if (targetWidget)
+ targetWidget->setFocus();
+ return (targetWidget != 0);
+}
+
+/*!
+ \internal
+
+ Searches for a widget that is positioned in the \a direction, starting
+ from the current focusWidget.
+
+ Returns the pointer to a found widget or 0, if there was no widget in
+ that direction.
+*/
+QWidget *QWidgetPrivate::widgetInNavigationDirection(Direction direction)
+{
+ const QWidget *sourceWidget = QApplication::focusWidget();
+ if (!sourceWidget)
+ return 0;
+ const QRect sourceRect = sourceWidget->rect().translated(sourceWidget->mapToGlobal(QPoint()));
+ const int sourceX =
+ (direction == DirectionNorth || direction == DirectionSouth) ?
+ (sourceRect.left() + (sourceRect.right() - sourceRect.left()) / 2)
+ :(direction == DirectionEast ? sourceRect.right() : sourceRect.left());
+ const int sourceY =
+ (direction == DirectionEast || direction == DirectionWest) ?
+ (sourceRect.top() + (sourceRect.bottom() - sourceRect.top()) / 2)
+ :(direction == DirectionSouth ? sourceRect.bottom() : sourceRect.top());
+ const QPoint sourcePoint(sourceX, sourceY);
+ const QPoint sourceCenter = sourceRect.center();
+ const QWidget *sourceWindow = sourceWidget->window();
+
+ QWidget *targetWidget = 0;
+ int shortestDistance = INT_MAX;
+ foreach(QWidget *targetCandidate, QApplication::allWidgets()) {
+ const QRect targetCandidateRect = targetCandidate->rect().translated(targetCandidate->mapToGlobal(QPoint()));
+ if ( targetCandidate != sourceWidget
+ && targetCandidate->focusPolicy() & Qt::TabFocus
+ && !(direction == DirectionNorth && targetCandidateRect.bottom() > sourceRect.top())
+ && !(direction == DirectionEast && targetCandidateRect.left() < sourceRect.right())
+ && !(direction == DirectionSouth && targetCandidateRect.top() < sourceRect.bottom())
+ && !(direction == DirectionWest && targetCandidateRect.right() > sourceRect.left())
+ && targetCandidate->isEnabled()
+ && targetCandidate->isVisible()
+ && targetCandidate->window() == sourceWindow) {
+ const int targetCandidateDistance = pointToRect(sourcePoint, targetCandidateRect);
+ if (targetCandidateDistance < shortestDistance) {
+ shortestDistance = targetCandidateDistance;
+ targetWidget = targetCandidate;
+ }
+ }
+ }
+ return targetWidget;
+}
+#endif
+
/*!
\preliminary
\since 4.2