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