src/hbcore/vkbhosts/private/hbvkbgeometrylogic_p.cpp
changeset 30 80e4d18b72f5
parent 28 b7da29130b0e
--- a/src/hbcore/vkbhosts/private/hbvkbgeometrylogic_p.cpp	Fri Sep 17 08:32:10 2010 +0300
+++ b/src/hbcore/vkbhosts/private/hbvkbgeometrylogic_p.cpp	Mon Oct 04 00:38:12 2010 +0300
@@ -32,6 +32,7 @@
 const qreal HbContainerBorderMargin = 20.0;
 const qreal HbEditorExtraMargin = 17.0;
 
+
 /*!
     \class HbVkbGeometryLogicPrivate
     \brief Calculates screen movement in cases the keyboard would overlap with editor
@@ -42,6 +43,7 @@
 
 */
 
+
 /*!
     \internal
     \brief Construct current state object screen status.
@@ -63,17 +65,21 @@
         const QSizeF& screenSize,
         const QSizeF& keypadSize,
         const QRectF& sceneArea,
+        bool isPopupType,
         bool isVkbOpen,
         bool hideTitlebar,
         bool hideStatusbar,
         const QRectF& containerArea,
         const QRectF& editorArea,
         const QRectF& cursorArea)
+            :
+        mIsPopupType(isPopupType)
 {
     // We need to consider situation, when keyboard is already on the screen, in
     // which case, titlebar and statusbar are already hidden, thus bigger visible area
-    // is already in use, so no adjustments needed.
-    if ( isVkbOpen ) {
+    // is already in use, so no adjustments needed. Popups can always use full visible
+    // area.
+    if ( isVkbOpen || isPopupType ) {
         mVisibleArea = QRectF(0.0, 0.0, screenSize.width(), screenSize.height() - keypadSize.height());
         mAdjust = 0.0;
     } else if ( hideTitlebar || hideStatusbar ) {
@@ -89,22 +95,103 @@
         mAdjust = 0.0;
     }
 
-    // Find out the container area.
+    // Find out the container area. No margin adjustments for popups.
     mContainerArea = containerArea;
-    mContainerArea.adjust(0.0, -HbContainerBorderMargin, 0.0, HbContainerBorderMargin);
+    if (isPopupType) {
+        mContainerArea.adjust(0.0, -HbContainerBorderMargin, 0.0, HbContainerBorderMargin);
+    }
     mContainerArea.translate(QPointF(0, mAdjust));
 
     // Find out the editor bounding box and add a small margin to height.
     mEditorArea = editorArea;
-    mEditorArea.adjust(0.0, -HbCursorLineMargin, 0.0, HbCursorLineMargin);
+    mEditorArea.adjust(0.0, -HbEditorExtraMargin, 0.0, HbEditorExtraMargin);
     mEditorArea.translate(QPointF(0, mAdjust));
 
     // Finally, get cursor size and adjust it little bit
     mCursorArea = cursorArea;
-    mCursorArea.adjust(0.0, -HbEditorExtraMargin, 0.0, HbEditorExtraMargin);
+    mCursorArea.adjust(0.0, -HbCursorLineMargin, 0.0, HbCursorLineMargin);
     mCursorArea.translate(QPointF(0, mAdjust));
 }
 
+
+/*!
+    \internal
+    \brief Check the source area fits inside target area.
+*/
+bool HbVkbGeometryLogicPrivate::minimunMovement(QPointF& vector) const
+{
+    vector.rx() = 0.0;
+    vector.ry() = mAdjust;
+    return false;
+}
+
+
+/*!
+    \internal
+    \brief Calculates vector to move given area to visible area.
+    \param areaToMove contains rectangle, which needs to be moved to visible area.
+
+    When moving editor to visible area, we need to consider situation, where
+    margins of the editor border may make editor look like it is outside of the
+    container. So every check we made, we need to compare against editor border
+    and container border.
+
+    \return Vector to visible area.
+*/
+bool HbVkbGeometryLogicPrivate::calculateVectorToVisibleArea(QPointF& vector, const QRectF& areaToMove) const
+{
+    qreal aTop = areaToMove.top();
+    qreal vTop = mVisibleArea.top();
+    qreal cTop = mContainerArea.top();
+
+    qreal aBottom = areaToMove.bottom();
+    qreal vBottom = mVisibleArea.bottom();
+    qreal cBottom = mContainerArea.bottom();
+
+    QRectF areaOfInterest = areaToMove;
+
+    // To simplify everything, first check, whether there is need to inspect
+    // container movement issues or not.
+    if ( !mContainerArea.contains(areaOfInterest) ) {
+        // Now we know, that area we are supposed to move, cannot be used
+        // in situations, when too close to borders and movement direction
+        // tells us to move container.
+        bool shouldMoveUp = aBottom > vBottom;
+        bool areaBelowContainer = aBottom > cBottom;
+        bool shouldMoveDown = aTop < vTop;
+        bool areaAboveContainer = aTop < cTop;
+
+        if ( ( areaBelowContainer && shouldMoveUp ) ||
+             ( areaAboveContainer && shouldMoveDown ) ) {
+            areaOfInterest = mContainerArea;
+        }
+    }
+
+    // Area is inside container. Before anything, check if we
+    // can move the container at least little bit. But it cannot be moved
+    // too low.
+    if ( areaOfInterest != mContainerArea && aTop < vTop ) {
+        qreal upward = aTop - mAdjust;
+
+        if ( upward < 0 ) {
+            vector.ry() -= upward;
+            return true;
+        } else {
+            return false;
+        }
+
+    // Vector calculation is simple, just figure out direction.
+    } else if ( aTop < vTop ) {
+        vector = QPointF(0.0, -aTop);
+        return true;
+
+    } else {
+        vector = QPointF(0.0, vBottom - areaOfInterest.bottom());
+        return true;
+    }
+}
+
+
 /*!
     \internal
     \brief Check the source area fits inside target area.
@@ -114,6 +201,7 @@
     return source.width() <= target.width() && source.height() <= target.height();
 }
 
+
 /*!
     \internal
     \brief Checks, whether the container fits into the visible area.
@@ -128,6 +216,7 @@
      return fitsArea(mVisibleArea, mContainerArea);
 }
 
+
 /*!
     \internal
     \brief Checks, whether the editor fits into the visible area.
@@ -143,6 +232,7 @@
     return fitsArea(mVisibleArea, mEditorArea);
 }
 
+
 /*!
     \internal
     \brief Check if container is fully visible.
@@ -154,71 +244,132 @@
     return mVisibleArea.contains(mContainerArea);
 }
 
+
 /*!
     \internal
-    \return True, when editor inside visible area
+    \return
 */
 bool HbVkbGeometryLogicPrivate::isEditorVisible() const
 {
     return mVisibleArea.contains(mEditorArea);
 }
 
+
 /*!
     \internal
-    \return True, when cursor inside visible area
+    \return
 */
 bool HbVkbGeometryLogicPrivate::isCursorVisible() const
 {
-    // Check wheter cursor inside the visible area.
+    // Check whether cursor inside the visible area.
     return mVisibleArea.contains(mCursorArea);
 }
 
+
 /*!
     \internal
-    \brief Calculates movement vector for viewport.
-
-    \return True, when container needs to be moved.
+    \return
 */
 bool HbVkbGeometryLogicPrivate::calculateContainerMovement(QPointF& vector) const
 {
+    // Clear any data away from the vector
+    vector = QPointF(0, 0);
+
+    // First check against invalid case. If cursor is not inside container, the
+    // data provided is incorrect.
+    if ( !mContainerArea.contains(mCursorArea) ) {
+        return false;
+
+    } else if ( containerFitsVisibleArea() ) {
+        return calculateContainerVector(vector);
+
+    } else if ( mIsPopupType ) {
+        return calculatePopupVector(vector);
+
     // In case editor or cursor inside visible area, no extra movement needed.
-    if ( isCursorVisible() ) {
-        vector.rx() = 0.0;
-        vector.ry() = mAdjust;
-        return false;
-    }
+    } else if ( isCursorVisible() ) {
+        return minimunMovement(vector);
 
     // At this point we know, that cursor is not inside of visible area,
     // after VKB has been shown. To make it bit prettier, let's check, if we can
     // move and fit the whole editor into the screen at once.
-    if ( !isEditorVisible() && editorFitsVisibleArea() ) {
-        // Editor is not in screen but fits there, so simply move the whole editor
-        // to screen. Only thing yet to check is, which direction the editor needs
-        // to be moved.
-        if ( mEditorArea.top() <= mVisibleArea.top() ) {
-            vector = QPointF(0.0, -mEditorArea.top());
-        } else {
-            // In case editor is not inside visible area, move editor until it is.
-            vector = QPointF(0.0, mVisibleArea.bottom() - mEditorArea.bottom());
-        }
+    } else if ( !isEditorVisible() && editorFitsVisibleArea() ) {
+        return calculateEditorVector(vector);
 
-        vector.ry() += mAdjust;
-
-        // Vector has been calculated, so finish the story and return.
-        return true;
-    }
 
     // At this point we know, that cursor is not visible and the editor does not fit
     // into the visible area. Here we need to move editor, so that the cursor can be
     // seen in the visible area. There are two ways to do this.
     // 1) Move container, until bottom of editor is reached OR
     // 2) Move container, until cursor hits top of the screen
-    int cursorMove = (int)(mVisibleArea.top() - mCursorArea.top());
-    int editorMove = (int)(mVisibleArea.bottom() - mEditorArea.bottom());
+    } else {
+        int cursorMove = static_cast<int>(mVisibleArea.top() - mCursorArea.top());
+        int editorMove = static_cast<int>(mVisibleArea.bottom() - mEditorArea.bottom());
+
+        // Choose smaller movement (notice usage of negative values)
+        vector = QPointF(0.0, cursorMove >= editorMove ? cursorMove : editorMove);
+
+        vector.ry() += mAdjust;
+        return true;
+    }
+}
+
+
+/*!
+    \internal
+    \return
+*/
+bool HbVkbGeometryLogicPrivate::calculateContainerVector(QPointF& vector) const
+{
+    if ( isContainerVisible() ) {
+        return minimunMovement(vector);
+    }
 
-    // Choose smaller movement (notice usage of negative values)
-    vector = QPointF(0.0, cursorMove >= editorMove ? cursorMove : editorMove);
+    bool result = calculateVectorToVisibleArea(vector, mContainerArea);
+    vector.ry() += mAdjust;
+    return result;
+}
+
+
+/*!
+    \internal
+    \brief Calculate vector to adjust popup location properly.
+
+    Goal of these calculations are to guarrantee, that the buttons are always
+    visible for user, so that the popup can be closed without closing VKB first.
+    This is achieved by trying to move popup bottom to edge of visible area,
+    and then check, whether the editor is still seen or not. If not, then adjust
+    the editor so, that it can be seen.
+
+    \return True, when movement needed
+*/
+bool HbVkbGeometryLogicPrivate::calculatePopupVector(QPointF& vector) const
+{
+    qreal mBottom = mContainerArea.bottom();
+    qreal vBottom = mVisibleArea.bottom();
+    vector.ry() += vBottom - mBottom;
+
+    QRectF newEditorPos = mEditorArea.translated(vector);
+    if (!mVisibleArea.contains(newEditorPos)) {
+        QPointF temp(0,0);
+        calculateVectorToVisibleArea(temp, newEditorPos);
+        vector += temp;
+    }
 
     vector.ry() += mAdjust;
+
     return true;
 }
+
+
+/*!
+    \internal
+    \return
+*/
+bool HbVkbGeometryLogicPrivate::calculateEditorVector(QPointF& vector) const
+{
+    bool result = calculateVectorToVisibleArea(vector, mEditorArea);
+    vector.ry() += mAdjust;
+    return result;
+}
+