diff options
author | Jarno Malmari <ext-jarno.malmari@nokia.com> | 2010-12-13 16:09:37 +0200 |
---|---|---|
committer | Adrian Yanes <ext-adrian.yanes@nokia.com> | 2010-12-21 10:24:00 +0100 |
commit | 90a9bbbc6fb8ca1b085a58c749e4cc492c38c449 (patch) | |
tree | 46a3260dfa812564cb91d6575018eb784dd5235f | |
parent | ee883860797c0d91aa2e1a8a4f9ff44e55275319 (diff) |
Fixes: NB#210697, [REG] Text Input Field is moved up while focus is set
RevBy: Michael Hasselmann, MichaĆ Guminiak
Details: Introduced a custom dynamic property which controls whether
a scrollable widget can be docked to vkb.
-rw-r--r-- | src/corelib/core/minputwidgetrelocator.cpp | 75 | ||||
-rw-r--r-- | src/corelib/core/minputwidgetrelocator.h | 6 | ||||
-rw-r--r-- | src/corelib/core/mscrollchain.cpp | 27 | ||||
-rw-r--r-- | src/corelib/core/mscrollchain.h | 11 | ||||
-rw-r--r-- | tests/ut_minputwidgetrelocator/ut_minputwidgetrelocator.cpp | 9 |
5 files changed, 123 insertions, 5 deletions
diff --git a/src/corelib/core/minputwidgetrelocator.cpp b/src/corelib/core/minputwidgetrelocator.cpp index 8d2e2f75..0187358c 100644 --- a/src/corelib/core/minputwidgetrelocator.cpp +++ b/src/corelib/core/minputwidgetrelocator.cpp @@ -28,12 +28,13 @@ #include "mrelocatorstyle.h" #include "mscrollchain.h" -#include <QDebug> #include <QGraphicsScene> #include <QGraphicsWidget> -#include <QTimer> namespace { + + const char * const BottomDockingProperty = "dockBottom"; + bool widgetDoesNotWantToBeScrolled(const QGraphicsWidget *widget) { // We don't know where to scroll QGraphicsWebView. We would only make things worse by trying. @@ -133,9 +134,11 @@ void MInputWidgetRelocator::update() const QRect microRect(microFocusRect(inputWidget)); if (microRect.isValid() && newChain->count() > 0) { + const bool widgetWasDocked = scrollDockedWidget(newChain, inputWidget, microRect); - // Check whether we need to do anything. - if (needsRelocation(inputWidget, microRect)) { + // If widget was not docked then use the regular rules with nogo zones + // and an anchor point. + if (!widgetWasDocked && needsRelocation(inputWidget, microRect)) { // Calculate anchor point in root coordinates const QPoint anchorPoint(rootElement->mapFromItem(inputWidget, microRect.topLeft()).x(), @@ -334,7 +337,68 @@ bool MInputWidgetRelocator::isWidgetRectFullyVisible(const QGraphicsWidget *widg { // Widget can be clipped by a nested pannable viewport. return !widget->isClipped() - || widget->clipPath().contains(localRect); + || widget->clipPath().boundingRect().contains(localRect); +} + +bool MInputWidgetRelocator::scrollDockedWidget(MScrollChain *chain, + const QGraphicsWidget *inputWidget, + const QRect µRect) +{ + // Find if we have scroller that wants to be docked to bottom. + const QGraphicsWidget *dockWidget = 0; + int dockWidgetId = -1; + for (int i = 0; i < chain->count(); ++i) { + QVariant dockBottom(chain->widgetAt(i)->property(BottomDockingProperty)); + if (dockBottom.isValid() + && dockBottom.toBool()) { + dockWidgetId = i; + dockWidget = chain->widgetAt(i); + break; + } + } + + if (!dockWidget) { + return false; + } + + // This is the rectangle we need to dock and preferably even keep it fully visible. + const QRect dockWidgetRect(dockWidget->rect().toRect()); + + // Origin of the rectangle has to be given to the chain in inputWidget coordinates. + const QPoint originPoint = inputWidget->mapFromItem(dockWidget, + dockWidgetRect.topLeft()).toPoint(); + + // Calculate target rectangle for the widget to be docked. + QRect targetRect = rootElement->mapRectFromItem(dockWidget, dockWidgetRect).toRect(); + + bool chainChanged = false; + + // Dock the widget if only it's not already at correct position. + if (targetRect.bottom() != exposedContentRect().bottom() + || !isWidgetRectFullyVisible(dockWidget, dockWidgetRect)) { + + // Move it to bottom of exposed content rectangle. + targetRect.moveBottom(exposedContentRect().bottom()); + + // Docking is done by parents of the dockWidget, therefore start at the next scroller. + chain->addBottomUpScroll(targetRect, originPoint, dockWidgetId + 1); + + chainChanged = true; + } + + // We still need to bring cursor visible, although we cannot guarantee it because + // docking at a right place is of higher priority. Use dockWidget and its children + // scrollers to scroll cursor rectangle visible. Don't touch parents of dockWidget. + if (!isWidgetRectFullyVisible(inputWidget, microRect)) { + chain->addMinimalScroll(microRect, 0, dockWidgetId); + chainChanged = true; + } + + if (chainChanged) { + chain->applyScrolling(); + } + + return true; } void MInputWidgetRelocator::centerContextWidgetToAnchorPoint(MScrollChain *newChain, @@ -345,6 +409,7 @@ void MInputWidgetRelocator::centerContextWidgetToAnchorPoint(MScrollChain *newCh const int yTarget = qMax<int>(exposedContentRect().top(), anchorPoint.y() - contextWidget->size().height() / 2); const QRect targetRect(QPoint(anchorPoint.x(), yTarget), contextWidget->size().toSize()); + const QPoint originPoint(contextWidget->mapToItem(inputWidget, 0, 0).toPoint()); newChain->addBottomUpScroll(targetRect, originPoint, 1); } diff --git a/src/corelib/core/minputwidgetrelocator.h b/src/corelib/core/minputwidgetrelocator.h index 158ca9b6..c79233de 100644 --- a/src/corelib/core/minputwidgetrelocator.h +++ b/src/corelib/core/minputwidgetrelocator.h @@ -133,6 +133,12 @@ private: bool isWidgetRectFullyVisible(const QGraphicsWidget *widget, const QRect &localRect) const; + //! If chain contains a dockable widget, dock it and return true. + //! Otherwise return false. + bool scrollDockedWidget(MScrollChain *chain, + const QGraphicsWidget *inputWidget, + const QRect µRect); + void centerContextWidgetToAnchorPoint(MScrollChain *newChain, const QPoint &anchorPoint, const QGraphicsWidget *inputWidget); diff --git a/src/corelib/core/mscrollchain.cpp b/src/corelib/core/mscrollchain.cpp index a292ec32..0d4ecd7f 100644 --- a/src/corelib/core/mscrollchain.cpp +++ b/src/corelib/core/mscrollchain.cpp @@ -61,6 +61,24 @@ void MScrollChain::addBottomUpScroll(const QRect &targetRect, } } +void MScrollChain::addMinimalScroll(const QRect &localRect, + int startingIndex, + int untilIndex) +{ + untilIndex = qBound<int>(0, untilIndex, chainItems.count() - 1); + startingIndex = qBound<int>(0, startingIndex, untilIndex); + + for (int i = startingIndex; i <= untilIndex; ++i) { + ScrollChainItem &chainItem(chainItems[i]); + + // Map target rectangle and origin point to delegate widget's local coordinates. + QRect delegateRect = mapToChainItemFromScrollTarget(chainItem, localRect); + + // Scroll the chain item. + chainItem.calculateScrolling(delegateRect, delegateRect.topLeft()); + } +} + void MScrollChain::applyScrolling() { for (ChainItemList::iterator item = chainItems.begin(); item != chainItems.end(); ++item) { @@ -198,6 +216,15 @@ QPoint MScrollChain::mapToChainItemFromScrollTarget(const ScrollChainItem &item, return mappedPoint; } + +QRect MScrollChain::mapToChainItemFromScrollTarget(const ScrollChainItem &item, + const QRect &rect) +{ + QRect moved = rect; + moved.moveTo(mapToChainItemFromScrollTarget(item, rect.topLeft())); + return moved; +} + QSharedPointer<MAbstractScroller> MScrollChain::findScrollerDelegate(const QGraphicsWidget *widget) const { QSharedPointer<MAbstractScroller> result; diff --git a/src/corelib/core/mscrollchain.h b/src/corelib/core/mscrollchain.h index c2c3d29b..95df896c 100644 --- a/src/corelib/core/mscrollchain.h +++ b/src/corelib/core/mscrollchain.h @@ -73,6 +73,15 @@ public: const QPoint &originPoint, int startingIndex = 0); + /*! \brief Scrolls the chain with minimal change in child-to-parent order. + * + * Calling this ensures that the given \localRect is made visible with + * minimal scrolling. + */ + void addMinimalScroll(const QRect &localRect, + int startingIndex, + int untilIndex); + /*! \brief Applies the planned scrolling * * Widgets are not expected to have finished their scrolling when this returns. @@ -142,6 +151,8 @@ private: QRect mapToChainItemFromRoot(const ScrollChainItem &item, const QRect &rect) const; QPoint mapToChainItemFromRoot(const ScrollChainItem &item, const QPoint &point) const; QPoint mapToChainItemFromScrollTarget(const ScrollChainItem &item, const QPoint &point); + QRect mapToChainItemFromScrollTarget(const ScrollChainItem &item, + const QRect &rect); private: typedef QMap<const QMetaObject *, QSharedPointer<MAbstractScroller> > ScrollerDelegateMap; diff --git a/tests/ut_minputwidgetrelocator/ut_minputwidgetrelocator.cpp b/tests/ut_minputwidgetrelocator/ut_minputwidgetrelocator.cpp index 123e77f9..e065965b 100644 --- a/tests/ut_minputwidgetrelocator/ut_minputwidgetrelocator.cpp +++ b/tests/ut_minputwidgetrelocator/ut_minputwidgetrelocator.cpp @@ -380,6 +380,15 @@ void MScrollChain::addBottomUpScroll(const QRect &targetRect, const QPoint &orig Q_UNUSED(index); } +void MScrollChain::addMinimalScroll(const QRect &localRect, + int startingIndex, + int untilIndex) +{ + Q_UNUSED(localRect); + Q_UNUSED(startingIndex); + Q_UNUSED(untilIndex); +} + void MScrollChain::applyScrolling() { ++gScrollCallCount; |