src/hbcore/vkbhosts/private/hbvkbgeometrylogic_p.cpp
changeset 30 80e4d18b72f5
parent 28 b7da29130b0e
equal deleted inserted replaced
28:b7da29130b0e 30:80e4d18b72f5
    30 
    30 
    31 const qreal HbCursorLineMargin = 15.0;
    31 const qreal HbCursorLineMargin = 15.0;
    32 const qreal HbContainerBorderMargin = 20.0;
    32 const qreal HbContainerBorderMargin = 20.0;
    33 const qreal HbEditorExtraMargin = 17.0;
    33 const qreal HbEditorExtraMargin = 17.0;
    34 
    34 
       
    35 
    35 /*!
    36 /*!
    36     \class HbVkbGeometryLogicPrivate
    37     \class HbVkbGeometryLogicPrivate
    37     \brief Calculates screen movement in cases the keyboard would overlap with editor
    38     \brief Calculates screen movement in cases the keyboard would overlap with editor
    38 
    39 
    39     This class contains calculations and logic to move screen in cases, when upcoming
    40     This class contains calculations and logic to move screen in cases, when upcoming
    40     keyboard would overlap the editor so, that text written could not be seen. Idea is
    41     keyboard would overlap the editor so, that text written could not be seen. Idea is
    41     to minimize the movement as much as possible.
    42     to minimize the movement as much as possible.
    42 
    43 
    43 */
    44 */
       
    45 
    44 
    46 
    45 /*!
    47 /*!
    46     \internal
    48     \internal
    47     \brief Construct current state object screen status.
    49     \brief Construct current state object screen status.
    48 
    50 
    61 */
    63 */
    62 HbVkbGeometryLogicPrivate::HbVkbGeometryLogicPrivate(
    64 HbVkbGeometryLogicPrivate::HbVkbGeometryLogicPrivate(
    63         const QSizeF& screenSize,
    65         const QSizeF& screenSize,
    64         const QSizeF& keypadSize,
    66         const QSizeF& keypadSize,
    65         const QRectF& sceneArea,
    67         const QRectF& sceneArea,
       
    68         bool isPopupType,
    66         bool isVkbOpen,
    69         bool isVkbOpen,
    67         bool hideTitlebar,
    70         bool hideTitlebar,
    68         bool hideStatusbar,
    71         bool hideStatusbar,
    69         const QRectF& containerArea,
    72         const QRectF& containerArea,
    70         const QRectF& editorArea,
    73         const QRectF& editorArea,
    71         const QRectF& cursorArea)
    74         const QRectF& cursorArea)
       
    75             :
       
    76         mIsPopupType(isPopupType)
    72 {
    77 {
    73     // We need to consider situation, when keyboard is already on the screen, in
    78     // We need to consider situation, when keyboard is already on the screen, in
    74     // which case, titlebar and statusbar are already hidden, thus bigger visible area
    79     // which case, titlebar and statusbar are already hidden, thus bigger visible area
    75     // is already in use, so no adjustments needed.
    80     // is already in use, so no adjustments needed. Popups can always use full visible
    76     if ( isVkbOpen ) {
    81     // area.
       
    82     if ( isVkbOpen || isPopupType ) {
    77         mVisibleArea = QRectF(0.0, 0.0, screenSize.width(), screenSize.height() - keypadSize.height());
    83         mVisibleArea = QRectF(0.0, 0.0, screenSize.width(), screenSize.height() - keypadSize.height());
    78         mAdjust = 0.0;
    84         mAdjust = 0.0;
    79     } else if ( hideTitlebar || hideStatusbar ) {
    85     } else if ( hideTitlebar || hideStatusbar ) {
    80         // Without titlebar and statusbar, the visible area is from the top of the screen
    86         // Without titlebar and statusbar, the visible area is from the top of the screen
    81         // to the top of the keyboard. Also, container needs to move slightly, when
    87         // to the top of the keyboard. Also, container needs to move slightly, when
    87         // bottom of the titlebar to top of the keyboard. No container movement needed.
    93         // bottom of the titlebar to top of the keyboard. No container movement needed.
    88         mVisibleArea = QRectF(0.0, 0.0, screenSize.width(), sceneArea.height() - keypadSize.height());
    94         mVisibleArea = QRectF(0.0, 0.0, screenSize.width(), sceneArea.height() - keypadSize.height());
    89         mAdjust = 0.0;
    95         mAdjust = 0.0;
    90     }
    96     }
    91 
    97 
    92     // Find out the container area.
    98     // Find out the container area. No margin adjustments for popups.
    93     mContainerArea = containerArea;
    99     mContainerArea = containerArea;
    94     mContainerArea.adjust(0.0, -HbContainerBorderMargin, 0.0, HbContainerBorderMargin);
   100     if (isPopupType) {
       
   101         mContainerArea.adjust(0.0, -HbContainerBorderMargin, 0.0, HbContainerBorderMargin);
       
   102     }
    95     mContainerArea.translate(QPointF(0, mAdjust));
   103     mContainerArea.translate(QPointF(0, mAdjust));
    96 
   104 
    97     // Find out the editor bounding box and add a small margin to height.
   105     // Find out the editor bounding box and add a small margin to height.
    98     mEditorArea = editorArea;
   106     mEditorArea = editorArea;
    99     mEditorArea.adjust(0.0, -HbCursorLineMargin, 0.0, HbCursorLineMargin);
   107     mEditorArea.adjust(0.0, -HbEditorExtraMargin, 0.0, HbEditorExtraMargin);
   100     mEditorArea.translate(QPointF(0, mAdjust));
   108     mEditorArea.translate(QPointF(0, mAdjust));
   101 
   109 
   102     // Finally, get cursor size and adjust it little bit
   110     // Finally, get cursor size and adjust it little bit
   103     mCursorArea = cursorArea;
   111     mCursorArea = cursorArea;
   104     mCursorArea.adjust(0.0, -HbEditorExtraMargin, 0.0, HbEditorExtraMargin);
   112     mCursorArea.adjust(0.0, -HbCursorLineMargin, 0.0, HbCursorLineMargin);
   105     mCursorArea.translate(QPointF(0, mAdjust));
   113     mCursorArea.translate(QPointF(0, mAdjust));
   106 }
   114 }
   107 
   115 
       
   116 
   108 /*!
   117 /*!
   109     \internal
   118     \internal
   110     \brief Check the source area fits inside target area.
   119     \brief Check the source area fits inside target area.
   111 */
   120 */
       
   121 bool HbVkbGeometryLogicPrivate::minimunMovement(QPointF& vector) const
       
   122 {
       
   123     vector.rx() = 0.0;
       
   124     vector.ry() = mAdjust;
       
   125     return false;
       
   126 }
       
   127 
       
   128 
       
   129 /*!
       
   130     \internal
       
   131     \brief Calculates vector to move given area to visible area.
       
   132     \param areaToMove contains rectangle, which needs to be moved to visible area.
       
   133 
       
   134     When moving editor to visible area, we need to consider situation, where
       
   135     margins of the editor border may make editor look like it is outside of the
       
   136     container. So every check we made, we need to compare against editor border
       
   137     and container border.
       
   138 
       
   139     \return Vector to visible area.
       
   140 */
       
   141 bool HbVkbGeometryLogicPrivate::calculateVectorToVisibleArea(QPointF& vector, const QRectF& areaToMove) const
       
   142 {
       
   143     qreal aTop = areaToMove.top();
       
   144     qreal vTop = mVisibleArea.top();
       
   145     qreal cTop = mContainerArea.top();
       
   146 
       
   147     qreal aBottom = areaToMove.bottom();
       
   148     qreal vBottom = mVisibleArea.bottom();
       
   149     qreal cBottom = mContainerArea.bottom();
       
   150 
       
   151     QRectF areaOfInterest = areaToMove;
       
   152 
       
   153     // To simplify everything, first check, whether there is need to inspect
       
   154     // container movement issues or not.
       
   155     if ( !mContainerArea.contains(areaOfInterest) ) {
       
   156         // Now we know, that area we are supposed to move, cannot be used
       
   157         // in situations, when too close to borders and movement direction
       
   158         // tells us to move container.
       
   159         bool shouldMoveUp = aBottom > vBottom;
       
   160         bool areaBelowContainer = aBottom > cBottom;
       
   161         bool shouldMoveDown = aTop < vTop;
       
   162         bool areaAboveContainer = aTop < cTop;
       
   163 
       
   164         if ( ( areaBelowContainer && shouldMoveUp ) ||
       
   165              ( areaAboveContainer && shouldMoveDown ) ) {
       
   166             areaOfInterest = mContainerArea;
       
   167         }
       
   168     }
       
   169 
       
   170     // Area is inside container. Before anything, check if we
       
   171     // can move the container at least little bit. But it cannot be moved
       
   172     // too low.
       
   173     if ( areaOfInterest != mContainerArea && aTop < vTop ) {
       
   174         qreal upward = aTop - mAdjust;
       
   175 
       
   176         if ( upward < 0 ) {
       
   177             vector.ry() -= upward;
       
   178             return true;
       
   179         } else {
       
   180             return false;
       
   181         }
       
   182 
       
   183     // Vector calculation is simple, just figure out direction.
       
   184     } else if ( aTop < vTop ) {
       
   185         vector = QPointF(0.0, -aTop);
       
   186         return true;
       
   187 
       
   188     } else {
       
   189         vector = QPointF(0.0, vBottom - areaOfInterest.bottom());
       
   190         return true;
       
   191     }
       
   192 }
       
   193 
       
   194 
       
   195 /*!
       
   196     \internal
       
   197     \brief Check the source area fits inside target area.
       
   198 */
   112 bool HbVkbGeometryLogicPrivate::fitsArea(const QRectF& target, const QRectF& source) const
   199 bool HbVkbGeometryLogicPrivate::fitsArea(const QRectF& target, const QRectF& source) const
   113 {
   200 {
   114     return source.width() <= target.width() && source.height() <= target.height();
   201     return source.width() <= target.width() && source.height() <= target.height();
   115 }
   202 }
       
   203 
   116 
   204 
   117 /*!
   205 /*!
   118     \internal
   206     \internal
   119     \brief Checks, whether the container fits into the visible area.
   207     \brief Checks, whether the container fits into the visible area.
   120 
   208 
   125 */
   213 */
   126 bool HbVkbGeometryLogicPrivate::containerFitsVisibleArea() const
   214 bool HbVkbGeometryLogicPrivate::containerFitsVisibleArea() const
   127 {
   215 {
   128      return fitsArea(mVisibleArea, mContainerArea);
   216      return fitsArea(mVisibleArea, mContainerArea);
   129 }
   217 }
       
   218 
   130 
   219 
   131 /*!
   220 /*!
   132     \internal
   221     \internal
   133     \brief Checks, whether the editor fits into the visible area.
   222     \brief Checks, whether the editor fits into the visible area.
   134 
   223 
   141 bool HbVkbGeometryLogicPrivate::editorFitsVisibleArea() const
   230 bool HbVkbGeometryLogicPrivate::editorFitsVisibleArea() const
   142 {
   231 {
   143     return fitsArea(mVisibleArea, mEditorArea);
   232     return fitsArea(mVisibleArea, mEditorArea);
   144 }
   233 }
   145 
   234 
       
   235 
   146 /*!
   236 /*!
   147     \internal
   237     \internal
   148     \brief Check if container is fully visible.
   238     \brief Check if container is fully visible.
   149 
   239 
   150     \return True, when fully inside visible area, otherwise false.
   240     \return True, when fully inside visible area, otherwise false.
   152 bool HbVkbGeometryLogicPrivate::isContainerVisible() const
   242 bool HbVkbGeometryLogicPrivate::isContainerVisible() const
   153 {
   243 {
   154     return mVisibleArea.contains(mContainerArea);
   244     return mVisibleArea.contains(mContainerArea);
   155 }
   245 }
   156 
   246 
   157 /*!
   247 
   158     \internal
   248 /*!
   159     \return True, when editor inside visible area
   249     \internal
       
   250     \return
   160 */
   251 */
   161 bool HbVkbGeometryLogicPrivate::isEditorVisible() const
   252 bool HbVkbGeometryLogicPrivate::isEditorVisible() const
   162 {
   253 {
   163     return mVisibleArea.contains(mEditorArea);
   254     return mVisibleArea.contains(mEditorArea);
   164 }
   255 }
   165 
   256 
   166 /*!
   257 
   167     \internal
   258 /*!
   168     \return True, when cursor inside visible area
   259     \internal
       
   260     \return
   169 */
   261 */
   170 bool HbVkbGeometryLogicPrivate::isCursorVisible() const
   262 bool HbVkbGeometryLogicPrivate::isCursorVisible() const
   171 {
   263 {
   172     // Check wheter cursor inside the visible area.
   264     // Check whether cursor inside the visible area.
   173     return mVisibleArea.contains(mCursorArea);
   265     return mVisibleArea.contains(mCursorArea);
   174 }
   266 }
   175 
   267 
   176 /*!
   268 
   177     \internal
   269 /*!
   178     \brief Calculates movement vector for viewport.
   270     \internal
   179 
   271     \return
   180     \return True, when container needs to be moved.
       
   181 */
   272 */
   182 bool HbVkbGeometryLogicPrivate::calculateContainerMovement(QPointF& vector) const
   273 bool HbVkbGeometryLogicPrivate::calculateContainerMovement(QPointF& vector) const
   183 {
   274 {
       
   275     // Clear any data away from the vector
       
   276     vector = QPointF(0, 0);
       
   277 
       
   278     // First check against invalid case. If cursor is not inside container, the
       
   279     // data provided is incorrect.
       
   280     if ( !mContainerArea.contains(mCursorArea) ) {
       
   281         return false;
       
   282 
       
   283     } else if ( containerFitsVisibleArea() ) {
       
   284         return calculateContainerVector(vector);
       
   285 
       
   286     } else if ( mIsPopupType ) {
       
   287         return calculatePopupVector(vector);
       
   288 
   184     // In case editor or cursor inside visible area, no extra movement needed.
   289     // In case editor or cursor inside visible area, no extra movement needed.
   185     if ( isCursorVisible() ) {
   290     } else if ( isCursorVisible() ) {
   186         vector.rx() = 0.0;
   291         return minimunMovement(vector);
   187         vector.ry() = mAdjust;
       
   188         return false;
       
   189     }
       
   190 
   292 
   191     // At this point we know, that cursor is not inside of visible area,
   293     // At this point we know, that cursor is not inside of visible area,
   192     // after VKB has been shown. To make it bit prettier, let's check, if we can
   294     // after VKB has been shown. To make it bit prettier, let's check, if we can
   193     // move and fit the whole editor into the screen at once.
   295     // move and fit the whole editor into the screen at once.
   194     if ( !isEditorVisible() && editorFitsVisibleArea() ) {
   296     } else if ( !isEditorVisible() && editorFitsVisibleArea() ) {
   195         // Editor is not in screen but fits there, so simply move the whole editor
   297         return calculateEditorVector(vector);
   196         // to screen. Only thing yet to check is, which direction the editor needs
   298 
   197         // to be moved.
       
   198         if ( mEditorArea.top() <= mVisibleArea.top() ) {
       
   199             vector = QPointF(0.0, -mEditorArea.top());
       
   200         } else {
       
   201             // In case editor is not inside visible area, move editor until it is.
       
   202             vector = QPointF(0.0, mVisibleArea.bottom() - mEditorArea.bottom());
       
   203         }
       
   204 
       
   205         vector.ry() += mAdjust;
       
   206 
       
   207         // Vector has been calculated, so finish the story and return.
       
   208         return true;
       
   209     }
       
   210 
   299 
   211     // At this point we know, that cursor is not visible and the editor does not fit
   300     // At this point we know, that cursor is not visible and the editor does not fit
   212     // into the visible area. Here we need to move editor, so that the cursor can be
   301     // into the visible area. Here we need to move editor, so that the cursor can be
   213     // seen in the visible area. There are two ways to do this.
   302     // seen in the visible area. There are two ways to do this.
   214     // 1) Move container, until bottom of editor is reached OR
   303     // 1) Move container, until bottom of editor is reached OR
   215     // 2) Move container, until cursor hits top of the screen
   304     // 2) Move container, until cursor hits top of the screen
   216     int cursorMove = (int)(mVisibleArea.top() - mCursorArea.top());
   305     } else {
   217     int editorMove = (int)(mVisibleArea.bottom() - mEditorArea.bottom());
   306         int cursorMove = static_cast<int>(mVisibleArea.top() - mCursorArea.top());
   218 
   307         int editorMove = static_cast<int>(mVisibleArea.bottom() - mEditorArea.bottom());
   219     // Choose smaller movement (notice usage of negative values)
   308 
   220     vector = QPointF(0.0, cursorMove >= editorMove ? cursorMove : editorMove);
   309         // Choose smaller movement (notice usage of negative values)
   221 
   310         vector = QPointF(0.0, cursorMove >= editorMove ? cursorMove : editorMove);
       
   311 
       
   312         vector.ry() += mAdjust;
       
   313         return true;
       
   314     }
       
   315 }
       
   316 
       
   317 
       
   318 /*!
       
   319     \internal
       
   320     \return
       
   321 */
       
   322 bool HbVkbGeometryLogicPrivate::calculateContainerVector(QPointF& vector) const
       
   323 {
       
   324     if ( isContainerVisible() ) {
       
   325         return minimunMovement(vector);
       
   326     }
       
   327 
       
   328     bool result = calculateVectorToVisibleArea(vector, mContainerArea);
   222     vector.ry() += mAdjust;
   329     vector.ry() += mAdjust;
       
   330     return result;
       
   331 }
       
   332 
       
   333 
       
   334 /*!
       
   335     \internal
       
   336     \brief Calculate vector to adjust popup location properly.
       
   337 
       
   338     Goal of these calculations are to guarrantee, that the buttons are always
       
   339     visible for user, so that the popup can be closed without closing VKB first.
       
   340     This is achieved by trying to move popup bottom to edge of visible area,
       
   341     and then check, whether the editor is still seen or not. If not, then adjust
       
   342     the editor so, that it can be seen.
       
   343 
       
   344     \return True, when movement needed
       
   345 */
       
   346 bool HbVkbGeometryLogicPrivate::calculatePopupVector(QPointF& vector) const
       
   347 {
       
   348     qreal mBottom = mContainerArea.bottom();
       
   349     qreal vBottom = mVisibleArea.bottom();
       
   350     vector.ry() += vBottom - mBottom;
       
   351 
       
   352     QRectF newEditorPos = mEditorArea.translated(vector);
       
   353     if (!mVisibleArea.contains(newEditorPos)) {
       
   354         QPointF temp(0,0);
       
   355         calculateVectorToVisibleArea(temp, newEditorPos);
       
   356         vector += temp;
       
   357     }
       
   358 
       
   359     vector.ry() += mAdjust;
       
   360 
   223     return true;
   361     return true;
   224 }
   362 }
       
   363 
       
   364 
       
   365 /*!
       
   366     \internal
       
   367     \return
       
   368 */
       
   369 bool HbVkbGeometryLogicPrivate::calculateEditorVector(QPointF& vector) const
       
   370 {
       
   371     bool result = calculateVectorToVisibleArea(vector, mEditorArea);
       
   372     vector.ry() += mAdjust;
       
   373     return result;
       
   374 }
       
   375