diff options
author | Alessandro Portale <aportale@trolltech.com> | 2009-09-19 11:37:38 (GMT) |
---|---|---|
committer | Alessandro Portale <aportale@trolltech.com> | 2009-09-19 11:37:38 (GMT) |
commit | cd48ed92670a0d086589b202364f38f14e7221c9 (patch) | |
tree | a3e9d51e75822a1380699d7cd5fb87ee1522239d /src/gui/kernel | |
parent | 3581668cd0ffbe47a05ce7467f8d89b8c9bb6101 (diff) | |
download | Qt-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')
-rw-r--r-- | src/gui/kernel/qapplication.cpp | 15 | ||||
-rw-r--r-- | src/gui/kernel/qwidget.cpp | 90 | ||||
-rw-r--r-- | src/gui/kernel/qwidget_p.h | 12 |
3 files changed, 104 insertions, 13 deletions
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 0ff7314..df4a935 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4781,13 +4781,13 @@ void QApplicationPrivate::emitLastWindowClosed() \note On Windows CE this feature is disabled by default for touch device mkspecs. To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined. - + \note On Symbian, setting the mode to Qt::NavigationModeCursorAuto will enable a virtual mouse cursor on non touchscreen devices, which is controlled by the cursor keys if there is no analog pointer device. On other platforms and on touchscreen devices, it has the same meaning as Qt::NavigationModeNone. - + \since 4.6 \sa keypadNavigationEnabled() @@ -4810,10 +4810,10 @@ void QApplication::setNavigationMode(Qt::NavigationMode mode) \note On Windows CE this feature is disabled by default for touch device mkspecs. To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined. - + \note On Symbian, the default mode is Qt::NavigationModeNone for touch devices, and Qt::NavigationModeKeypadDirectional. - + \since 4.6 \sa keypadNavigationEnabled() @@ -4829,12 +4829,11 @@ Qt::NavigationMode QApplication::navigationMode() This feature is available in Qt for Embedded Linux, Symbian and Windows CE only. - \note On Windows CE this feature is disabled by default for touch device mkspecs. To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined. - + \deprecated \sa setNavigationMode() @@ -4846,7 +4845,7 @@ void QApplication::setKeypadNavigationEnabled(bool enable) QApplication::setNavigationMode(Qt::NavigationModeKeypadDirectional); #else QApplication::setNavigationMode(Qt::NavigationModeKeypadTabOrder); -#endif +#endif } else { QApplication::setNavigationMode(Qt::NavigationModeNone); @@ -4863,7 +4862,7 @@ void QApplication::setKeypadNavigationEnabled(bool enable) \note On Windows CE this feature is disabled by default for touch device mkspecs. To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined. - + \deprecated \sa navigationMode() 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 diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 7eb8f04..5e06c29 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -252,6 +252,13 @@ public: CloseWithSpontaneousEvent }; + enum Direction { + DirectionNorth = 0x01, + DirectionEast = 0x10, + DirectionSouth = 0x02, + DirectionWest = 0x20 + }; + // Functions. explicit QWidgetPrivate(int version = QObjectPrivateVersion); ~QWidgetPrivate(); @@ -398,6 +405,11 @@ public: void updateFrameStrut(); QRect frameStrut() const; +#ifdef QT_KEYPAD_NAVIGATION + static bool navigateToDirection(Direction direction); + static QWidget *widgetInNavigationDirection(Direction direction); +#endif + void setWindowIconText_sys(const QString &cap); void setWindowIconText_helper(const QString &cap); void setWindowTitle_sys(const QString &cap); |