ganeswidgets/src/hggridcontainer.cpp
changeset 19 31a1a9e11046
parent 5 4fa04caf0f43
child 20 a60f8b6b1d32
--- a/ganeswidgets/src/hggridcontainer.cpp	Fri Sep 17 08:35:50 2010 +0300
+++ b/ganeswidgets/src/hggridcontainer.cpp	Mon Oct 04 02:07:13 2010 +0300
@@ -18,14 +18,11 @@
 #include <QGesture>
 #include <QPainter>
 #include <QTimer>
-#include <HbLabel>
 #include <HbGridViewItem>
 #include <HbMainWindow>
 #include "hggridcontainer.h"
 #include "hgmediawallrenderer.h"
 #include "hgquad.h"
-#include "hgvgquadrenderer.h"
-#include "hgvgimage.h"
 #include "hgwidgetitem.h"
 #include "trace.h"
 
@@ -33,29 +30,94 @@
 #include <HbIconItem>
 #include <QAbstractItemModel>
 #include "hglongpressvisualizer.h"
-
+#include <HbPinchGesture>
+#include <QGraphicsSceneMouseEvent>
 
 static const qreal KCameraMaxYAngle(20);
 static const qreal KSpringVelocityToCameraYAngleFactor(2);
 
 HgGridContainer::HgGridContainer(QGraphicsItem *parent) :
     HgContainer(parent),
-    mEffect3dEnabled(true)
+    mEffect3dEnabled(true),
+    mPinchEnabled(false),
+    mPinchingOngoing(false),
+    mTempImageHeightForLineGrid(-1),
+    mTempImageHeightFinal(-1),
+    mTempRowCount(-1),
+    mPinchEndAlreadyHandled(false),
+    mReactToOnlyPanGestures(false),
+    mHorizontalRowCount(3),
+    mVerticalColumnCount(3),
+    mHorizontalPinchLevels(QPair<int,int>(2,3)),
+    mVerticalPinchLevels(QPair<int,int>(2,5))
 {
-
     mUserItemSize = QSize(120,120);
-    mUserItemSpacing = QSize(1,1);
-
+    mUserItemSpacing = QSize(0,0);
 }
 
 HgGridContainer::~HgGridContainer()
 {
-    
 }
 
 void HgGridContainer::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
 {
     HgContainer::paint(painter, option, widget);
+
+    // Draw these only while pinching
+    if(mPinchingOngoing)
+    {         
+        const QPen& oldPen = painter->pen();
+        
+        // dim the background, i.e. draw trasparent black screen-sized rect (alpha is 100 of 255)
+        painter->fillRect(rect(), QColor(0, 0, 0, 100));
+        
+        QPen pen = painter->pen();
+        pen.setColor(Qt::white);
+        pen.setWidth(4);
+        painter->setPen(pen);
+        
+        int imageXCount;
+        int imageYCount;
+        int widthSpacingPlusImage;
+        int heightSpacingPlusImage;
+        // Use temp values that are updated during pinching
+        QSize imageSize(mTempImageHeightForLineGrid, mTempImageHeightForLineGrid);
+        
+        if (scrollDirection() == Qt::Horizontal )   //landscape mode
+        {
+            imageXCount = rect().width() / imageSize.width();
+            imageYCount = mTempRowCount;
+            widthSpacingPlusImage = mRenderer->getSpacing().height() + imageSize.height();
+            heightSpacingPlusImage = mRenderer->getSpacing().width() + imageSize.width();
+        }
+        else                                        //portrait mode
+        {
+            imageXCount = mTempRowCount;
+            imageYCount = rect().height() / imageSize.height();
+            widthSpacingPlusImage = mRenderer->getSpacing().width() + imageSize.width();
+            heightSpacingPlusImage = mRenderer->getSpacing().height() + imageSize.height();
+        }
+        
+        int yOffset(0);
+        if (scrollDirection() == Qt::Horizontal ) {            
+            yOffset = (rect().height() - (mUserItemSize.height()*mHorizontalRowCount))/2;
+        }
+        
+        for (int xCounter = 0; xCounter < (imageXCount+1); ++xCounter)
+        {
+            for (int yCounter = 0; yCounter < (imageYCount+1); ++yCounter)
+            {
+                painter->drawLine(QPoint(0, yOffset + yCounter * heightSpacingPlusImage), 
+                                  QPoint(rect().width(), yOffset + yCounter * heightSpacingPlusImage));
+            }
+            
+            painter->drawLine(QPoint(xCounter * widthSpacingPlusImage, yOffset), 
+                              QPoint(xCounter * widthSpacingPlusImage, rect().height()-yOffset));
+        }
+        
+        painter->setPen(oldPen);
+        
+    }
     
     updateSelectedItem();
 }
@@ -66,7 +128,8 @@
     HgMediaWallRenderer* renderer = new HgMediaWallRenderer(this, scrollDirection, scrollDirection, false);
     renderer->enableCoverflowMode(false);
     renderer->setImageSize(mUserItemSize);
-    renderer->setRowCount(3, renderer->getImageSize(), false);    
+    const int rowCount = scrollDirection == Qt::Horizontal ? mHorizontalRowCount : mVerticalColumnCount;
+    renderer->setRowCount(rowCount, renderer->getImageSize(), false);    
     renderer->enableReflections(false);
     renderer->setSpacing(mUserItemSpacing);
     renderer->setFrontCoverElevationFactor(0.5);    
@@ -90,21 +153,43 @@
     return qBound(-KCameraMaxYAngle, springVelocity * KSpringVelocityToCameraYAngleFactor, KCameraMaxYAngle);
 }
 
-void HgGridContainer::handleTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
+bool HgGridContainer::handleTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
 {
     Q_UNUSED(pos)
-    Q_UNUSED(hitItemIndex)
-        
-    selectItem(hitItemIndex);                
-    emit activated(hitItem->modelIndex());                        
+
+    if (mSelectionMode != HgWidget::NoSelection) {
+        return handleItemSelection(hitItem);
+    }
+    
+    if (!mIgnoreGestureAction) {
+        selectItem(hitItemIndex);
+        emit activated(hitItem->modelIndex());
+    } else {
+        mSpring.resetVelocity();
+        update();
+        mIgnoreGestureAction = false;
+    }
+    return true;
 }
 
-void HgGridContainer::handleLongTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
+bool HgGridContainer::handleLongTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
 {
     Q_UNUSED(hitItemIndex)
     
+    INFO("Long tap:" << hitItem->modelIndex().row());
+    
     selectItem(hitItemIndex);
-    emit longPressed(hitItem->modelIndex(), pos);    
+    
+    if (!mIgnoreGestureAction) {
+        if (mHandleLongPress){
+            emit longPressed(hitItem->modelIndex(), pos);
+        }
+    } else {
+        mSpring.resetVelocity();
+        update();
+        mIgnoreGestureAction = false;
+    }
+    return true;
 }
 
 void HgGridContainer::onScrollPositionChanged(qreal pos)
@@ -112,7 +197,7 @@
     HgContainer::onScrollPositionChanged(pos);
 
     if (pos < 0) return;    
-    const int index = ((int)pos)*rowCount();
+    const int index = ((int)pos)*currentRowCount();
     if (index > itemCount()) return;
     
     HgWidgetItem* item = itemByIndex(index);
@@ -134,3 +219,357 @@
 {
     return mEffect3dEnabled;
 }
+
+bool HgGridContainer::handleTap(Qt::GestureState state, const QPointF &pos)
+{
+    FUNC_LOG;
+    
+    bool handleGesture = false;
+    
+    if (hasItemAt(pos)) {
+        switch (state) 
+            {
+            case Qt::GestureStarted:
+                {
+                // TODO IS THIS IF REALLY NEEDED
+                if(mSpring.isActive()) {                    
+                    qreal springPos = mSpring.pos().x();
+                    int gridTotalHeightInImages = ceilf( mItems.count() / mRenderer->getRowCount() );
+                    qreal currentViewHeightInImages;
+                    if (scrollDirection() == Qt::Horizontal ) {
+                        int rowHeight = mRenderer->getImageSize().width() + mRenderer->getSpacing().width();
+                        currentViewHeightInImages = rect().width() / rowHeight;
+                    } else {
+                        int rowHeight = mRenderer->getImageSize().height() + mRenderer->getSpacing().height();
+                        currentViewHeightInImages = rect().height() / rowHeight;
+                    }
+                    
+                    // If list does not currently fill the whole screen (some theme background behind the list
+                    // is visible), and list is moving, then do not react to tapping.
+                    if( springPos >= 0 
+                        && springPos <= (gridTotalHeightInImages - currentViewHeightInImages) ) {
+                        mSpring.cancel();
+                        mEmitScrollingEnded = true;
+                    }
+                    mIgnoreGestureAction = true;
+                } else if (mHandleLongPress){
+                    startLongPressWatcher(pos);
+                }
+                break;
+                }
+            case Qt::GestureFinished:
+                {
+                int hitItemindex = -1;
+                HgWidgetItem* hitItem = getItemAt(pos,hitItemindex);
+                handleGesture = handleTapAction(pos, hitItem, hitItemindex);
+                if (mEmitScrollingEnded) {
+                    mEmitScrollingEnded = false;
+                    emit scrollingEnded();
+                }
+                }
+            case Qt::GestureUpdated:
+            case Qt::GestureCanceled:
+            default:
+                stopLongPressWatcher();
+                break;
+            }
+        
+        handleGesture = true;
+    } else {
+        if (state == Qt::GestureFinished) {
+            mSpring.resetVelocity();
+            mSpring.cancel();
+            update();
+            emit emptySpacePressed();
+        }
+    }    
+    return handleGesture;
+}
+
+bool HgGridContainer::handleLongTap(Qt::GestureState state, const QPointF &pos)
+{
+    // HContainer handles the long tap if there is item at the pos.
+    bool handled = HgContainer::handleLongTap(state,pos);
+    if (!handled && state == Qt::GestureFinished) {
+        mSpring.resetVelocity();
+        mSpring.cancel();
+        update();
+        emit emptySpacePressed();
+    }
+    return handled;
+}
+
+void HgGridContainer::setPinchEnabled(bool pinchEnabled)
+{
+    if (mPinchEnabled != pinchEnabled) {
+        mPinchEnabled = pinchEnabled;
+        if (mPinchEnabled) {
+            grabGesture(Qt::PinchGesture);
+            iFadeAnimation.setTargetObject(this);
+            iFadeAnimation.setPropertyName("opacity");
+            iFadeAnimation.setDuration(500);
+            iFadeAnimation.setStartValue(1.0);
+            iFadeAnimation.setEndValue(0.0);
+            connect(&iFadeAnimation, SIGNAL(finished()), SLOT(effectFinished()));
+
+        } else {
+            iFadeAnimation.stop();
+            setOpacity(1);
+            disconnect(&iFadeAnimation,SIGNAL(finished()), this, SLOT(effectFinished()));
+            ungrabGesture(Qt::PinchGesture);
+        }
+    }
+}
+
+bool HgGridContainer::pinchEnabled() const
+{
+    return mPinchEnabled;
+}
+
+void HgGridContainer::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+    if(event->type() == QEvent::GraphicsSceneMousePress)
+    {
+        //reset, just in case
+        mPinchingOngoing = false;
+        mPinchEndAlreadyHandled = false;
+        mTempImageHeightForLineGrid = -1;
+        mTempImageHeightFinal = -1;
+    }
+}
+
+void HgGridContainer::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+    if(event->type() == QEvent::GraphicsSceneMouseRelease)
+    {
+        handlePinchEnd();
+    }
+}
+
+void HgGridContainer::gestureEvent(QGestureEvent* event)
+{
+    if (mItems.count() == 0) {
+        // we have no items so no need to handle the gesture.
+        event->ignore();
+        return;
+    }
+    
+    if (!mPinchingOngoing) {
+        HgContainer::gestureEvent(event);
+    }
+
+    bool eventHandled(false);
+    
+    QGesture* pinchGesture = event->gesture(Qt::PinchGesture);
+    if(mPinchEnabled && !mReactToOnlyPanGestures && pinchGesture)
+    {
+        HbPinchGesture* pinch = static_cast<HbPinchGesture *>(pinchGesture);
+        switch (pinch->state())
+            {
+            case Qt::GestureUpdated:
+                handlePinchUpdate( pinch );
+                break;
+            case Qt::GestureStarted:                
+                mTempRowCount = -1;         //reset, just in case
+                mTempImageHeightForLineGrid = -1;  //reset, just in case
+                mTempImageHeightFinal = -1;   //reset, just in case
+                iTargetRowCountList.clear();
+                mPinchingOngoing = true;
+                mPinchEndAlreadyHandled = false;
+                break;
+            case Qt::GestureCanceled:
+                mPinchingOngoing = false;
+                mPinchEndAlreadyHandled = true;
+                update();   //redraw
+                break;
+            case Qt::GestureFinished:
+                handlePinchEnd();
+                break;
+            default:
+                break;                
+            }
+        
+        eventHandled = true;
+    }    
+    
+    eventHandled ? event->accept() : event->ignore();
+}
+
+void HgGridContainer::handlePinchUpdate(HbPinchGesture* pinch)
+{
+    // while user is scaling down scale factor changes from 1 -> 0. When scaling up scale factor
+    // changes from 1 -> x
+    qreal change = 0.0;
+    qreal scaleFactor = pinch->scaleFactor();// + pinch->lastScaleFactor())/2;
+    if (scaleFactor < 1) {
+        change = -5*(1-scaleFactor);
+    } else {
+        change = scaleFactor - 1;
+    }    
+
+    qreal wannaBeRowCount = mRenderer->getRowCount() + change*1.5;
+    
+    int minRowCount = scrollDirection() == Qt::Horizontal ? 
+        mHorizontalPinchLevels.first : mVerticalPinchLevels.first;
+    int maxRowCount = scrollDirection() == Qt::Horizontal ? 
+        mHorizontalPinchLevels.second : mVerticalPinchLevels.second;
+    
+    if(wannaBeRowCount < minRowCount) {
+        wannaBeRowCount = minRowCount;
+    }
+    else if(wannaBeRowCount > maxRowCount) {
+        wannaBeRowCount = maxRowCount;
+    }
+
+    mTempRowCount = (int)wannaBeRowCount;
+
+    while (iTargetRowCountList.count() >= 4) {
+        iTargetRowCountList.dequeue();
+    }            
+        
+    iTargetRowCountList.enqueue(wannaBeRowCount);
+    
+    
+    qreal averageRowCount = 0;
+    int count = iTargetRowCountList.count();
+    if (count >= 2 ) {
+        averageRowCount += iTargetRowCountList.at(count-1);
+        averageRowCount += iTargetRowCountList.at(count-2);
+        averageRowCount /= 2;
+    } else {
+        averageRowCount = wannaBeRowCount;
+    }
+    
+    if (scrollDirection() == Qt::Horizontal ) {
+        int centerAreaheight = mUserItemSize.height()*mHorizontalRowCount; 
+        mTempImageHeightForLineGrid = (centerAreaheight - ((int)averageRowCount + 1) * mRenderer->getSpacing().height()) / averageRowCount;
+    } else {
+        mTempImageHeightForLineGrid = (rect().width() - ((int)averageRowCount + 1) * mRenderer->getSpacing().width()) / averageRowCount;
+    }
+    
+    update();   //redraw
+}
+
+void HgGridContainer::handlePinchEnd()
+{
+    if(mPinchingOngoing && !mPinchEndAlreadyHandled) {
+        mPinchingOngoing = false;
+        mPinchEndAlreadyHandled = true;
+        
+        qreal averageRowCount = 0;
+        int count = iTargetRowCountList.count();
+        while (!iTargetRowCountList.isEmpty()) {
+            qreal value = iTargetRowCountList.dequeue();
+            averageRowCount += value;
+        }
+        
+        averageRowCount /= count;
+
+        qreal temp = floorf(averageRowCount);
+        averageRowCount = (averageRowCount - temp > 0.5f) ? ceilf(averageRowCount) : temp;
+        mTempRowCount = averageRowCount;
+        
+        // change the row count if it has been changed by pinching
+        if ( (mTempRowCount != -1) 
+             && (mTempRowCount != mRenderer->getRowCount()) ) {
+        
+            if (scrollDirection() == Qt::Horizontal ) {
+                int centerAreaheight = mUserItemSize.height()*mHorizontalRowCount; 
+                mTempImageHeightFinal = (centerAreaheight - ((int)mTempRowCount + 1) * mRenderer->getSpacing().height()) / (int)mTempRowCount;
+            } else {
+                mTempImageHeightFinal = (rect().width() - ((int)mTempRowCount + 1) * mRenderer->getSpacing().width()) / (int)mTempRowCount;
+            }
+                            
+            mTargetRowCount = mTempRowCount;
+            mTargetImageSize = QSizeF(mTempImageHeightFinal,mTempImageHeightFinal);
+            iFadeAnimation.setDirection(QAbstractAnimation::Forward);
+            iFadeAnimation.start();
+        }
+    }
+}
+
+bool HgGridContainer::event(QEvent *e) 
+{    
+    if (e->type() == QEvent::TouchBegin)
+    {
+        // The TouchBegin event must be accepted (i.e. return true) to be able to receive Pinch events.
+        return true;
+    }
+    else if(e->type() == QEvent::Gesture)
+    {
+        // Since pinch gesture is not forwarded to 
+        // gestureEvent function so lets handle it here. 
+        QGestureEvent* gesture = static_cast<QGestureEvent*>(e);
+        gestureEvent(gesture);
+        return true;
+    }
+
+    return QGraphicsObject::event(e);
+}
+
+void HgGridContainer::effectFinished()
+{
+    if (iFadeAnimation.direction() == QAbstractAnimation::Forward) {
+        mRenderer->setRowCount(mTargetRowCount, mTargetImageSize);
+        mRenderer->setImageSize(mTargetImageSize);
+//        mSpring.setDamping( mTargetRowCount != 3 ? 
+//            KSpringDampingScrolling*(mTargetRowCount-3)*4 : KSpringDampingScrolling );
+//        mSpring.setK( mTargetRowCount != 3 ? 
+//            KSpringKScrolling/((mTargetRowCount-3)*4) : KSpringKScrolling );
+        scrollTo(mSelectionModel->currentIndex());
+        iFadeAnimation.setDirection(QAbstractAnimation::Backward);
+        iFadeAnimation.start();
+    }
+}
+
+void HgGridContainer::setRowCount(int count, Qt::Orientation scrollDirection)
+{
+    if (scrollDirection == Qt::Horizontal) {
+        mHorizontalRowCount = count;
+    } else {
+        mVerticalColumnCount = count;
+    }
+}
+
+int HgGridContainer::rowCount(Qt::Orientation scrollDirection) const
+{
+    return scrollDirection == Qt::Horizontal ? mHorizontalRowCount : mVerticalColumnCount;
+}
+
+void HgGridContainer::setOrientation(Qt::Orientation orientation, bool animate)
+{
+    HgContainer::setOrientation(orientation, animate);
+    
+    if (orientation == Qt::Horizontal) {
+            mRenderer->enableReflections(false);
+            mRenderer->setImageSize(mUserItemSize);
+        if (currentRowCount() != mHorizontalRowCount) {
+            mRenderer->setRowCount(mHorizontalRowCount, mUserItemSize, false);
+            scrollTo(mSelectionModel->currentIndex());
+        }
+    } else {
+        mRenderer->enableReflections(false);
+        mRenderer->setImageSize(mUserItemSize);
+        if (currentRowCount() != mVerticalColumnCount) {
+            mRenderer->setRowCount(mVerticalColumnCount, mUserItemSize, false);        
+            scrollTo(mSelectionModel->currentIndex());
+        }
+    }
+}
+
+void HgGridContainer::setPinchLevels(QPair<int,int> levels, Qt::Orientation scrollDirection)
+{
+    if (scrollDirection == Qt::Horizontal) {
+        mHorizontalPinchLevels = levels;
+    } else {
+        mVerticalPinchLevels = levels;
+    }
+}
+
+QPair<int,int> HgGridContainer::pinchLevels(Qt::Orientation scrollDirection) const
+{
+    return scrollDirection == Qt::Horizontal ? 
+        mHorizontalPinchLevels : mVerticalPinchLevels;
+}
+
+// End of file