homescreenapp/hsdomainmodel/src/hswidgetpositioningonwidgetadd.cpp
changeset 90 3ac3aaebaee5
child 95 32e56106abf2
equal deleted inserted replaced
86:e4f038c420f7 90:3ac3aaebaee5
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 #include <QLineF>
       
    19 #include <QtGlobal>
       
    20 #include <QPointF>
       
    21 #include <math.h>
       
    22 
       
    23 #include "hswidgetpositioningonwidgetadd.h"
       
    24 #include "hsconfiguration.h"
       
    25 #include "hsgui.h"
       
    26 
       
    27 const qreal offset = 20; //TODO: Implement this as configurable parameter
       
    28 
       
    29 
       
    30 /*!
       
    31     \class HsWidgetPositioningOnWidgetAdd
       
    32     \ingroup group_hsutils
       
    33     \brief 
       
    34 */
       
    35 
       
    36 /*!
       
    37     \class HsWidgetPositioningOnWidgetAdd
       
    38     \brief Defines widget positioning on widget add.
       
    39 
       
    40     Widget positioning on widget add sets positions for
       
    41     a set of home screen widgets added from application library.
       
    42 */
       
    43 
       
    44 /*!
       
    45     Sets the positioning \a instance as the current one.
       
    46     Deletes the existing instance if present.
       
    47 */
       
    48 void HsWidgetPositioningOnWidgetAdd::setInstance(
       
    49     HsWidgetPositioningOnWidgetAdd *instance)
       
    50 {
       
    51     if (mInstance)
       
    52         delete mInstance;
       
    53     mInstance = instance;
       
    54 }
       
    55  
       
    56 /*!
       
    57     Returns the current positioning instance.
       
    58 */
       
    59 HsWidgetPositioningOnWidgetAdd *HsWidgetPositioningOnWidgetAdd::instance()
       
    60 {
       
    61     return mInstance;
       
    62 }
       
    63 
       
    64 /*!
       
    65     Stores the current positioning instance.
       
    66 */
       
    67 HsWidgetPositioningOnWidgetAdd *HsWidgetPositioningOnWidgetAdd::mInstance = 0;
       
    68 
       
    69 /*!
       
    70     \class HsAnchorPointInBottomRight
       
    71     \brief Diagonal widget positioning algorithm.
       
    72     
       
    73     Sets widget's lower right corner to follow content area's diagonal.
       
    74     Widgets are positioned to certain offset to each other.
       
    75 */
       
    76 QList<QRectF> HsAnchorPointInBottomRight::convert(
       
    77     const QRectF &contentArea,
       
    78     const QList<QRectF> &existingRects,
       
    79     const QList<QRectF> &newRects,
       
    80     const QPointF &startPoint)
       
    81 {
       
    82     Q_UNUSED(existingRects);
       
    83 
       
    84     QList<QRectF> toGeometries;
       
    85 
       
    86     //Offset for widgets' bottom right position to each other
       
    87     qreal k = contentArea.height()/contentArea.width(); //slope of the diagonal
       
    88     qreal offset_x = offset/(sqrt(k + 1));
       
    89     qreal offset_y = k*offset_x;
       
    90     QPointF offsetPoint(offset_x, offset_y);
       
    91     
       
    92     QPointF anchorPoint;
       
    93    
       
    94     if(startPoint.isNull()){
       
    95 
       
    96         QLineF diagonal(contentArea.topLeft(), contentArea.bottomRight());
       
    97         QLineF widgetRightSide(contentArea.center().x()+ newRects.at(0).width()/2,
       
    98                            contentArea.top(),
       
    99                            contentArea.center().x()+ newRects.at(0).width()/2,
       
   100                            contentArea.bottom());
       
   101 
       
   102         // right side line intersection with diagonal will be bottom right position
       
   103         // for the first rect
       
   104         if(QLineF::BoundedIntersection != 
       
   105             diagonal.intersect(widgetRightSide, &anchorPoint)) {
       
   106             return newRects; //Return original since undefined error.
       
   107                             //In this case widget's must be wider than the content area.
       
   108         }
       
   109     }else{
       
   110         anchorPoint = startPoint - offsetPoint;
       
   111     }
       
   112 
       
   113     QRectF widgetRect;
       
   114     for(int i=0;i<newRects.count();++i) {
       
   115         widgetRect = newRects.at(i);
       
   116         widgetRect.moveBottomRight(anchorPoint);
       
   117         //if widget rect doesn't fit, try to move it
       
   118         if(!contentArea.contains(widgetRect)) {
       
   119             /*! precondition is that
       
   120              widget's max height < content area height
       
   121              widget's max widht < content area width
       
   122             */
       
   123             widgetRect.moveBottomRight(contentArea.bottomRight());
       
   124             // anchorPoin is always previous bottom right
       
   125             anchorPoint = widgetRect.bottomRight();
       
   126         }
       
   127         toGeometries << widgetRect;
       
   128         anchorPoint -= offsetPoint;
       
   129         
       
   130     }
       
   131     return toGeometries;
       
   132 }
       
   133 
       
   134 /*!
       
   135     \class HsAnchorPointInCenter
       
   136     \brief Diagonal widget positioning algorithm.
       
   137     
       
   138     Sets widget's center point to follow content area's diagonal.
       
   139     Widgets are positioned to certain offset to each other.
       
   140 */
       
   141 #ifdef COVERAGE_MEASUREMENT
       
   142 #pragma CTC SKIP
       
   143 #endif //COVERAGE_MEASUREMENT
       
   144 QList<QRectF> HsAnchorPointInCenter::convert(
       
   145     const QRectF &contentArea,
       
   146     const QList<QRectF> &existingRects,
       
   147     const QList<QRectF> &newRects,
       
   148     const QPointF &startPoint )
       
   149 {
       
   150     Q_UNUSED(existingRects);
       
   151     Q_UNUSED(startPoint)
       
   152 
       
   153     QList<QRectF> toGeometries;
       
   154 
       
   155     //Offset for widgets' centers position to each other
       
   156     qreal k = contentArea.height()/contentArea.width(); //slope of the diagonal
       
   157     qreal offset_x = offset/(sqrt(k + 1));
       
   158     qreal offset_y = k*offset_x;
       
   159     QPointF offsetPoint(offset_x, offset_y);
       
   160 
       
   161     //First widget to the center of the content area
       
   162     QPointF anchorPoint = contentArea.center();
       
   163     foreach (QRectF g, newRects) {
       
   164         g.moveCenter(anchorPoint);
       
   165         toGeometries << g;
       
   166         anchorPoint -= offsetPoint;
       
   167         if(!contentArea.contains(anchorPoint)) {
       
   168             anchorPoint = contentArea.bottomRight();
       
   169         }
       
   170     }
       
   171     return toGeometries;
       
   172 }
       
   173 
       
   174 HsWidgetOrganizer::HsWidgetOrganizer(int anchorDistance,
       
   175                                      HsConfiguration::WidgetOrganizerSearchSequence sequence)
       
   176 : mAnchorDistance(anchorDistance), mSequence(sequence), mAnchorColumns(0), mAnchorRows(0),
       
   177   mCenterAlgorithm(new HsAnchorPointInCenter())
       
   178 {
       
   179 
       
   180 }
       
   181 
       
   182 HsWidgetOrganizer::~HsWidgetOrganizer()
       
   183 {
       
   184     delete mCenterAlgorithm;
       
   185 }
       
   186 
       
   187 /*!
       
   188     \class HsWidgetOrganizer
       
   189     \brief Advanced widget positioning algorithm.
       
   190     
       
   191     Organizes widget's starting from upper left corner towards right,
       
   192     and then continues the on the next line.
       
   193 */
       
   194 QList<QRectF> HsWidgetOrganizer::convert(
       
   195     const QRectF &contentArea,
       
   196     const QList<QRectF> &existingRects,
       
   197     const QList<QRectF> &newRects,
       
   198     const QPointF &startPoint)
       
   199 {
       
   200     Q_UNUSED(startPoint)
       
   201 
       
   202     // mandatory check ups
       
   203     if (mAnchorDistance <= 0 || contentArea == QRectF() ||
       
   204         newRects == QList<QRectF>()) {
       
   205         return QList<QRectF>();
       
   206     }
       
   207 
       
   208     // calculate anchor limits based on anchor distance
       
   209     mAnchorColumns = convertToAnchors(contentArea.width());
       
   210     mAnchorRows = convertToAnchors(contentArea.height());
       
   211     mContentArea = contentArea;
       
   212 
       
   213     // map rects so that we can later return them in original order
       
   214     QMap<int, QRectF> newRectsMap;
       
   215     for (int id = 0; id < newRects.count(); id++) {
       
   216         newRectsMap.insert(id, newRects.at(id));
       
   217     } 
       
   218 
       
   219     // get orientation
       
   220     Qt::Orientation orientation(HsGui::instance()->orientation());
       
   221 
       
   222     SortMode mode;
       
   223     // select sorting mode based on orientation and search sequence
       
   224     if((orientation == Qt::Vertical && mSequence == HsConfiguration::SearchRowByRow) ||
       
   225         (orientation == Qt::Horizontal && mSequence == HsConfiguration::SearchColumnByColumn)) {
       
   226         mode = SortByHeight;
       
   227     } else {
       
   228         mode = SortByWidth;
       
   229     }
       
   230 
       
   231     // sort rects into order
       
   232     QList<int> newRectsSorted = sortRects(mode, newRectsMap);
       
   233 
       
   234     // initialize anchor points
       
   235     initAnchors();
       
   236 
       
   237     // go through existing rects
       
   238     bool ok = checkExistingRects(existingRects);
       
   239     if (!ok) {
       
   240         return QList<QRectF>();
       
   241     }
       
   242 
       
   243     QList<int> newRectsNotCalculated;
       
   244     QList<QRectF> newExistingRects;
       
   245     newExistingRects += existingRects;
       
   246 
       
   247     // get positions for all new rects
       
   248     for (int i = 0; i < newRectsMap.count(); i++) {
       
   249         // proceed in sorted order with the rects
       
   250         QRectF newRect = newRectsMap.value(newRectsSorted.at(i));
       
   251         // find first free anchor point for rect
       
   252         QPointF position = getPosition(newRect.size());
       
   253         if (position != QPointF(-1,-1)) {
       
   254             QRectF calculatedGeometry = QRectF(position.x() + mContentArea.x(),
       
   255                                                position.y() + mContentArea.y(),
       
   256                                                newRect.width(), newRect.height());
       
   257             // update new rect instead of old one based on id map
       
   258             newRectsMap.insert(newRectsSorted.at(i), calculatedGeometry);
       
   259             // update existing rects
       
   260             newExistingRects << calculatedGeometry;
       
   261             // mark new rect reserved
       
   262             bool marked = markAnchors(QRectF(position, newRect.size()));
       
   263             if (!marked) {
       
   264                 return QList<QRectF>();
       
   265             }
       
   266 
       
   267         } else {
       
   268             // collect rect that do not fit
       
   269             newRectsNotCalculated << newRectsSorted.at(i);
       
   270         }
       
   271     }
       
   272 
       
   273     // use center algorithm with offset for the rest rects that did not fit to content area
       
   274     if (newRectsNotCalculated.count() > 0 ) {
       
   275         // collect not organized rects
       
   276         QList<QRectF> undoneRects;
       
   277         for (int i = 0; i < newRectsNotCalculated.count(); i++) {
       
   278             undoneRects << newRectsMap.value(newRectsNotCalculated.at(i));
       
   279         }
       
   280         QList<QRectF> calculatedRects =
       
   281             mCenterAlgorithm->convert(mContentArea, newExistingRects, undoneRects, QPointF());
       
   282         // update the rest rects instead of old ones
       
   283         for (int i = 0; i < calculatedRects.count(); i++) {
       
   284             newRectsMap.insert(newRectsNotCalculated.at(i), calculatedRects.at(i));
       
   285             /* take rect out of list and add it to the end of the list
       
   286                rect that do not fit are added in the end in users add order */
       
   287             // we need to map z values to correct widgets to enable this
       
   288            /*
       
   289             newRectsMap.take(newRectsNotCalculated.at(i));
       
   290             newRectsMap.insert(newRectsMap.count() + i + 1, calculatedRects.at(i));
       
   291            */
       
   292         }
       
   293     }
       
   294 
       
   295     return newRectsMap.values();
       
   296 }
       
   297 
       
   298 /*!    
       
   299     Initializes anchor point network for area size
       
   300 */
       
   301 void HsWidgetOrganizer::initAnchors()
       
   302 {
       
   303     // need to zero just in case (if algorithm is called twice)
       
   304     mAnchors = QList<bool>();
       
   305     // create anchor point network
       
   306     for (int i = 0; i < (mAnchorColumns * mAnchorRows); i++) {
       
   307         mAnchors.append(false);
       
   308     }
       
   309 }
       
   310 
       
   311 /*!    
       
   312     Check existing rects and marks them reserved
       
   313 */
       
   314 bool HsWidgetOrganizer::checkExistingRects(const QList<QRectF> &existingRects)
       
   315 {
       
   316     foreach (QRectF rect, existingRects) {
       
   317         /* if existing rect is on the edges of content area
       
   318            need to drop one pixels because there is no anchors on the edge */
       
   319         int rightmostPoint = rect.x() + rect.width();
       
   320         if (rightmostPoint == mContentArea.width()) {
       
   321             rect.setWidth(rect.width() - 1);
       
   322         }
       
   323         int undermostPoint = rect.y() + rect.height();
       
   324         if (undermostPoint == mContentArea.height()) {
       
   325             rect.setHeight(rect.height() - 1);
       
   326         }
       
   327         // decrease content area size in case it does not start from (0,0)
       
   328         rect = QRectF(
       
   329             QPointF(rect.x() - mContentArea.x(), rect.y() - mContentArea.y()),
       
   330             rect.size());
       
   331         bool marked = markAnchors(rect);
       
   332         if (!marked) {
       
   333             return false;
       
   334         }
       
   335     }
       
   336     return true;
       
   337 }
       
   338 
       
   339 /*!    
       
   340     Calculates pixel length as anchor points
       
   341 */
       
   342 int HsWidgetOrganizer::convertToAnchors(int length)
       
   343 {
       
   344     // calculate remainder
       
   345     int remainder = length % mAnchorDistance;
       
   346     // calculate anchor points (only pixel integrals are counted, decimals are cut away)
       
   347     int anchorPoints = (length - remainder) / mAnchorDistance;
       
   348     return anchorPoints;
       
   349 }
       
   350 
       
   351 /*!    
       
   352     Marks reserved anchor points based on given rects
       
   353 */
       
   354 bool HsWidgetOrganizer::markAnchors(const QRectF &rect)
       
   355 {
       
   356     // in case content does not start from zero, need take contentArea into calculations
       
   357     int startWidth = convertToAnchors(rect.x());
       
   358     int endWidth = convertToAnchors(rect.x() + rect.width());
       
   359     int startHeight = convertToAnchors(rect.y());
       
   360     int endHeight = convertToAnchors(rect.y() + rect.height());
       
   361 
       
   362     // mark reserved anchors row by row from left to right
       
   363     for (int i = startWidth; i <= endWidth; i++) {
       
   364         for (int j = startHeight; j <= endHeight; j++) {
       
   365             int index = getAnchorListIndex(QPointF(i,j));
       
   366             if (index < 0) {
       
   367                 return false;
       
   368             }
       
   369             mAnchors[index] = true;
       
   370         }
       
   371     }
       
   372     return true;
       
   373 }
       
   374 
       
   375 /*!    
       
   376     Returns anchor's list index based on given position
       
   377 */
       
   378 int HsWidgetOrganizer::getAnchorListIndex(const QPointF &position)
       
   379 {
       
   380     int index = (position.y() * mAnchorColumns) + position.x();
       
   381     if (index < mAnchors.count()) {
       
   382         return index;
       
   383     } else {
       
   384         return -1;
       
   385     }
       
   386 }
       
   387 
       
   388 /*!    
       
   389     Finds anchor points for content size
       
   390 */
       
   391 QPointF HsWidgetOrganizer::getPosition(const QSizeF &size)
       
   392 {
       
   393     QPointF startPoint(0,0);
       
   394     // convert units from pixels to anchors
       
   395     int width = convertToAnchors(size.width());
       
   396     int height = convertToAnchors(size.height());
       
   397 
       
   398     // based on search sequence, select position searching method
       
   399     if (mSequence == HsConfiguration::SearchRowByRow) {
       
   400         startPoint = searchPositionRowByRow(startPoint, width, height);
       
   401     } else {
       
   402         startPoint = searchPositionColumnByColumn(startPoint, width, height);
       
   403     }
       
   404 
       
   405     if (startPoint == QPointF(-1,-1)) {
       
   406         return startPoint;
       
   407     } else {
       
   408         // return the actual pixel coordinate
       
   409         return QPointF(startPoint.x() * mAnchorDistance, startPoint.y() * mAnchorDistance);
       
   410     }
       
   411 }
       
   412 
       
   413 /*!    
       
   414     Search sequence that finds anchor position by looking first for width on x-axis and
       
   415     then secondarily on height from y-axis
       
   416 */
       
   417 QPointF HsWidgetOrganizer::searchPositionRowByRow(QPointF startPoint, int width, int height)
       
   418 {
       
   419     bool anchorFound = false;
       
   420     QPointF candidatePoint(0,0);
       
   421     // loop until anchor point is found
       
   422     while (anchorFound == false) {
       
   423         // search for width on specified row
       
   424         candidatePoint = searchSpace(SearchRow, startPoint, width);
       
   425         if (candidatePoint != QPointF(-1,-1)) {
       
   426             // update start point to where found width starts
       
   427             startPoint.setX(candidatePoint.x());
       
   428             // check all anchor height points corresponding the found free width points
       
   429             for(int i = startPoint.x(); i <= startPoint.x() + width; i++) {
       
   430                 // save current start point to be checked
       
   431                 QPointF point = QPointF(i, startPoint.y());
       
   432                 // search for height on specified column
       
   433                 candidatePoint = searchSpace(SearchColumn, point, height);
       
   434                 if (candidatePoint == QPointF(-1,-1)) {
       
   435                     // update x anchor index
       
   436                     startPoint.setX(startPoint.x() + 1);
       
   437                     // set i to max to stop searching
       
   438                     i = startPoint.x() + width;
       
   439                 }
       
   440             }
       
   441             // if all height searches were successfull
       
   442             if (candidatePoint != QPointF(-1,-1)) {
       
   443                 anchorFound = true;
       
   444             }
       
   445         } else {
       
   446             // update x and y start positions when row has been checked
       
   447             startPoint.setX(0);
       
   448             startPoint.setY(startPoint.y() + 1);
       
   449             // check that enough height left
       
   450             if (startPoint.y() >= mAnchorRows) {
       
   451                 return QPointF(-1,-1);
       
   452             }
       
   453         }
       
   454     }
       
   455 
       
   456     return startPoint;
       
   457 }
       
   458 
       
   459 /*!    
       
   460     Search sequence that finds anchor position by looking first for height on y-axis and
       
   461     then secondarily on width from x-axis
       
   462 */
       
   463 QPointF HsWidgetOrganizer::searchPositionColumnByColumn(QPointF startPoint,
       
   464                                                         int width, int height)
       
   465 {
       
   466     bool anchorFound = false;
       
   467     QPointF candidatePoint(0,0);
       
   468 
       
   469     while (anchorFound == false) {
       
   470         candidatePoint = searchSpace(SearchColumn, startPoint, height);
       
   471         if (candidatePoint != QPointF(-1,-1)) {
       
   472             startPoint.setY(candidatePoint.y());
       
   473             for(int i = startPoint.y(); i <= startPoint.y() + height; i++) {
       
   474                 QPointF point = QPointF(startPoint.x(), i);
       
   475                 candidatePoint = searchSpace(SearchRow, point, width);
       
   476                 if (candidatePoint == QPointF(-1,-1)) {
       
   477                     startPoint.setY(startPoint.y() + 1);
       
   478                     i = startPoint.y() + height;
       
   479                 }
       
   480             }
       
   481             if (candidatePoint != QPointF(-1,-1)) {
       
   482                 anchorFound = true;
       
   483             }
       
   484         } else {
       
   485             startPoint.setY(0);
       
   486             startPoint.setX(startPoint.x() + 1);
       
   487             if (startPoint.x() >= mAnchorColumns) {
       
   488                 return QPointF(-1,-1);
       
   489             }
       
   490         }
       
   491     }
       
   492 
       
   493     return startPoint;
       
   494 }
       
   495 
       
   496 /*!    
       
   497     Searches anchor point space for given length
       
   498 */
       
   499 QPointF HsWidgetOrganizer::searchSpace(SearchMode mode, QPointF startPoint, int length)
       
   500 {
       
   501     int availableLength = 0;
       
   502     // convert start point to an index in anchor list
       
   503     int startIndex = getAnchorListIndex(startPoint);
       
   504     int increment = 0;
       
   505     int endIndex = 0;
       
   506 
       
   507     // set end anchor index depending on checked axis
       
   508     if (mode == SearchRow) {
       
   509         // save the last index of the checked row
       
   510         endIndex = getAnchorListIndex(QPointF((mAnchorColumns - 1), startPoint.y()));
       
   511 
       
   512     } else {
       
   513         // save the last index of the checked column
       
   514         endIndex = getAnchorListIndex(QPointF(startPoint.x(), (mAnchorRows - 1)));
       
   515         // we need to add increment due to anchors are listed row by row
       
   516         increment = mAnchorColumns - 1;
       
   517     }
       
   518 
       
   519     // safety checks
       
   520     if (startIndex == -1 || endIndex == -1) {
       
   521         return QPointF(-1,-1);
       
   522     }
       
   523 
       
   524     // loop through anchor indexes, increment is added only when going through height
       
   525     for (int i = startIndex; i <= endIndex; i = i + 1 + increment) {
       
   526         // if anchor reserved
       
   527         if (mAnchors.at(i) == true) {
       
   528             availableLength = 0;
       
   529             // if going through the first part of sequence (width/height)
       
   530             if ((mSequence == HsConfiguration::SearchRowByRow && mode == SearchRow) ||
       
   531                 (mSequence == HsConfiguration::SearchColumnByColumn && mode == SearchColumn)) {
       
   532                 // update start index
       
   533                 startIndex = i + 1 + increment;
       
   534             } else {
       
   535                 // exit immediately if second part of sequence fails
       
   536                 return QPointF(-1,-1);                
       
   537             }
       
   538         } else {
       
   539             // if enough space found
       
   540             if (availableLength == length) {
       
   541                 // return the actual anchor position
       
   542                 return getAnchorCoordinates(startIndex);
       
   543             }
       
   544             // update available length
       
   545             availableLength++;
       
   546         }
       
   547     }
       
   548 
       
   549     return QPointF(-1,-1);
       
   550 }
       
   551 
       
   552 /*!    
       
   553     Returns pixel coordinate based on anchor coordinate
       
   554 */
       
   555 QPointF HsWidgetOrganizer::getAnchorCoordinates(int index)
       
   556 {
       
   557     if (index < mAnchors.count()) {
       
   558         int x = index % mAnchorColumns;
       
   559         int y = (index - x) / mAnchorColumns;
       
   560         return QPointF(x,y);
       
   561     } else {
       
   562         return QPointF();
       
   563     }
       
   564 }
       
   565 
       
   566 /*!
       
   567     Sorts rects based on sort mode and given map of rects
       
   568 */
       
   569 QList<int> HsWidgetOrganizer::sortRects(SortMode mode, const QMap<int, QRectF> &rects)
       
   570 {
       
   571     QList<int> sortedRects;
       
   572     int i = 0;
       
   573     // loop through all rects
       
   574     QMapIterator<int, QRectF> id(rects);
       
   575     while (id.hasNext()) {
       
   576         id.next();
       
   577         int index = 0;
       
   578         // add first rect id to sorted list
       
   579         if (i == 0) {
       
   580             sortedRects << id.key();
       
   581         } else {
       
   582             // go through existing rects in the sorted list
       
   583             for ( int j = 0; j < sortedRects.count(); j++) {
       
   584                 // calculations for sortByArea
       
   585                 qreal existingArea = rects.value(sortedRects.at(j)).width() *
       
   586                                                  rects.value(sortedRects.at(j)).height();
       
   587                 qreal newArea = id.value().width() * id.value().height();
       
   588                 // sort rects in height order
       
   589                 switch (mode) {
       
   590                 case SortByHeight:
       
   591                     /* if rect heigth is smaller on already
       
   592                        existing ones in the list -> increment index
       
   593                     */
       
   594                     if (id.value().height() <= rects.value(sortedRects.at(j)).height()) {
       
   595                         index++;
       
   596                     }
       
   597                     break;
       
   598                 // sort rects in width order
       
   599                 case SortByWidth:
       
   600                     // if rect width is smaller -> increment index
       
   601                     if (id.value().width() <= rects.value(sortedRects.at(j)).width()) {
       
   602                         index++;
       
   603                     }
       
   604                     break;
       
   605                 case SortByArea:
       
   606                     // if rect area is smaller -> increment index
       
   607                     if (newArea <= existingArea) {
       
   608                         index++;
       
   609                     }
       
   610                 // otherwise return in original order
       
   611                 default:
       
   612                     index++;
       
   613                     break;
       
   614                 }
       
   615             }
       
   616             // add rect id in the sorted list
       
   617             sortedRects.insert(index, id.key());
       
   618         }
       
   619         i++;
       
   620     }
       
   621     return sortedRects;
       
   622 }
       
   623 
       
   624 #ifdef COVERAGE_MEASUREMENT
       
   625 #pragma CTC ENDSKIP
       
   626 #endif //COVERAGE_MEASUREMENT
       
   627