aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@digia.com>2013-02-22 13:44:06 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-03-12 02:27:29 +0100
commit2f9d0346f00e37725f0f1bce1318501a25c5e438 (patch)
tree24060fe2777ada4a054cb0c82e5bf89c28ffa70a /src/quick
parentb4673e69a0522fca9c592f1dab1734738b1443a8 (diff)
Support activeFocusOnTab in QQuickItem
Add activeFocusOnTab as property to QQuickItem. Setting the property allows automatic keyboard navigation between all elements that have it set. This key event handler will only be called after the QML key handlers, such as KeyNavigation and Keys, and the C++ key event handlers, such as keyPressEvent function. Algorithm is most done by Frederik Gladhorn, in cooperation with Gabriel de Dietrich. Done-with: Frederik Gladhorn <frederik.gladhorn@digia.com> Done-with: Gabriel de Dietrich <gabriel.dedietrich@digia.com> Change-Id: I8b58be9c20d113661fe85d27bdb1af84340d9de5 Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com> Reviewed-by: Frederik Gladhorn <frederik.gladhorn@digia.com>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/items/qquickitem.cpp157
-rw-r--r--src/quick/items/qquickitem.h5
-rw-r--r--src/quick/items/qquickitem_p.h6
3 files changed, 166 insertions, 2 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 53773553ee..67c4fd2140 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -1863,6 +1863,11 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
*/
/*!
+ \fn void QQuickItem::activeFocusOnTabChanged(bool)
+ \internal
+*/
+
+/*!
\fn void QQuickItem::childrenChanged()
\internal
*/
@@ -2023,6 +2028,93 @@ QQuickItem::~QQuickItem()
}
/*!
+ \internal
+ \brief QQuickItemPrivate::focusNextPrev focuses the next/prev item in the tab-focus-chain
+ \param item The item that currently has the focus
+ \param forward The direction
+ \return Whether the next item in the focus chain is found or not
+
+ If \a next is true, the next item visited will be in depth-first order relative to \a item.
+ If \a next is false, the next item visited will be in reverse depth-first order relative to \a item.
+*/
+bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward)
+{
+ Q_ASSERT(item);
+ Q_ASSERT(item->activeFocusOnTab());
+
+ QQuickItem *from = 0;
+ if (forward) {
+ from = item->parentItem();
+ } else {
+ if (!item->childItems().isEmpty())
+ from = item->childItems().first();
+ else
+ from = item->parentItem();
+ }
+ bool skip = false;
+ QQuickItem *current = item;
+ do {
+ skip = false;
+ QQuickItem *last = current;
+
+ bool hasChildren = !current->childItems().isEmpty() && current->isEnabled() && current->isVisible();
+
+ // coming from parent: check children
+ if (hasChildren && from == current->parentItem()) {
+ if (forward) {
+ current = current->childItems().first();
+ } else {
+ current = current->childItems().last();
+ if (!current->childItems().isEmpty())
+ skip = true;
+ }
+ } else if (hasChildren && forward && from != current->childItems().last()) {
+ // not last child going forwards
+ int nextChild = current->childItems().indexOf(from) + 1;
+ current = current->childItems().at(nextChild);
+ } else if (hasChildren && !forward && from != current->childItems().first()) {
+ // not first child going backwards
+ int prevChild = current->childItems().indexOf(from) - 1;
+ current = current->childItems().at(prevChild);
+ if (!current->childItems().isEmpty())
+ skip = true;
+ // back to the parent
+ } else if (current->parentItem()) {
+ current = current->parentItem();
+ // we would evaluate the parent twice, thus we skip
+ if (forward) {
+ skip = true;
+ } else if (!forward && !current->childItems().isEmpty()) {
+ if (last != current->childItems().first()) {
+ skip = true;
+ } else if (last == current->childItems().first()) {
+ if (current->isFocusScope() && current->activeFocusOnTab() && current->hasActiveFocus())
+ skip = true;
+ }
+ }
+ } else if (hasChildren) {
+ // Wrap around after checking all items forward
+ if (forward) {
+ current = current->childItems().first();
+ } else {
+ current = current->childItems().last();
+ if (!current->childItems().isEmpty())
+ skip = true;
+ }
+ }
+
+ from = last;
+ } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible());
+
+ if (current == item)
+ return false;
+
+ current->forceActiveFocus();
+
+ return true;
+}
+
+/*!
\qmlproperty Item QtQuick2::Item::parent
This property holds the visual parent of the item.
@@ -2522,6 +2614,7 @@ QQuickItemPrivate::QQuickItemPrivate()
, isAccessible(false)
, culled(false)
, hasCursor(false)
+ , activeFocusOnTab(false)
, dirtyAttributes(0)
, nextDirtyItem(0)
, prevDirtyItem(0)
@@ -4170,6 +4263,23 @@ void QQuickItemPrivate::deliverKeyEvent(QKeyEvent *e)
else
extra->keyHandler->keyReleased(e, true);
}
+
+ if (e->isAccepted())
+ return;
+
+ //only care about KeyPress now
+ if (q->activeFocusOnTab() && e->type() == QEvent::KeyPress) {
+ bool res = false;
+ if (!(e->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
+ if (e->key() == Qt::Key_Backtab
+ || (e->key() == Qt::Key_Tab && (e->modifiers() & Qt::ShiftModifier)))
+ res = QQuickItemPrivate::focusNextPrev(q, false);
+ else if (e->key() == Qt::Key_Tab)
+ res = QQuickItemPrivate::focusNextPrev(q, true);
+ if (res)
+ e->setAccepted(true);
+ }
+ }
}
#ifndef QT_NO_IM
@@ -5332,6 +5442,53 @@ void QQuickItem::setSmooth(bool smooth)
}
/*!
+ \qmlproperty bool QtQuick2::Item::activeFocusOnTab
+
+ This property holds whether the item wants to be in tab focus
+ chain. By default this is set to false.
+
+ The tab focus chain traverses elements by visiting first the
+ parent, and then its children in the order they occur in the
+ children property. Pressing the tab key on an item in the tab
+ focus chain will move keyboard focus to the next item in the
+ chain. Pressing BackTab (normally Shift+Tab) will move focus
+ to the previous item.
+
+ To set up a manual tab focus chain, see \l KeyNavigation. Tab
+ key events used by Keys or KeyNavigation have precedence over
+ focus chain behavior, ignore the events in other key handlers
+ to allow it to propagate.
+*/
+/*!
+ \property QQuickItem::activeFocusOnTab
+
+ This property holds whether the item wants to be in tab focus
+ chain. By default this is set to false.
+*/
+bool QQuickItem::activeFocusOnTab() const
+{
+ Q_D(const QQuickItem);
+ return d->activeFocusOnTab;
+}
+void QQuickItem::setActiveFocusOnTab(bool activeFocusOnTab)
+{
+ Q_D(QQuickItem);
+ if (d->activeFocusOnTab == activeFocusOnTab)
+ return;
+
+ if (window()) {
+ if ((this == window()->activeFocusItem()) && !activeFocusOnTab) {
+ qWarning("QQuickItem: Cannot set activeFocusOnTab to false once item is the active focus item.");
+ return;
+ }
+ }
+
+ d->activeFocusOnTab = activeFocusOnTab;
+
+ emit activeFocusOnTabChanged(activeFocusOnTab);
+}
+
+/*!
\qmlproperty bool QtQuick2::Item::antialiasing
Primarily used in Rectangle and image based elements to decide if the item should
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 71681698b9..c37bc10bdd 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -132,6 +132,7 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus
Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged FINAL)
Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged FINAL)
+ Q_PROPERTY(bool activeFocusOnTab READ activeFocusOnTab WRITE setActiveFocusOnTab NOTIFY activeFocusOnTabChanged FINAL)
Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
@@ -261,6 +262,9 @@ public:
bool smooth() const;
void setSmooth(bool);
+ bool activeFocusOnTab() const;
+ void setActiveFocusOnTab(bool);
+
bool antialiasing() const;
void setAntialiasing(bool);
@@ -345,6 +349,7 @@ Q_SIGNALS:
void stateChanged(const QString &);
void focusChanged(bool);
void activeFocusChanged(bool);
+ void activeFocusOnTabChanged(bool);
void parentChanged(QQuickItem *);
void transformOriginChanged(TransformOrigin);
void smoothChanged(bool);
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 8f6865b40b..4bd9d82c20 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -396,8 +396,8 @@ public:
bool antialiasing:1;
bool focus:1;
bool activeFocus:1;
- bool notifiedFocus:1;
// Bit 16
+ bool notifiedFocus:1;
bool notifiedActiveFocus:1;
bool filtersChildMouseEvents:1;
bool explicitVisible:1;
@@ -413,8 +413,8 @@ public:
bool isAccessible:1;
bool culled:1;
bool hasCursor:1;
- // bool dummy:1
// Bit 32
+ bool activeFocusOnTab:1;
enum DirtyType {
TransformOrigin = 0x00000001,
@@ -484,6 +484,8 @@ public:
QTransform itemToWindowTransform() const;
void itemToParentTransform(QTransform &) const;
+ static bool focusNextPrev(QQuickItem *item, bool forward);
+
qreal x;
qreal y;
qreal width;