diff -r 1ef5359bf0f4 -r a10844a9914d ganeswidgets/src/hggridcontainer.cpp --- a/ganeswidgets/src/hggridcontainer.cpp Fri Sep 03 10:22:04 2010 +0300 +++ b/ganeswidgets/src/hggridcontainer.cpp Fri Sep 17 15:55:58 2010 +0300 @@ -18,14 +18,11 @@ #include #include #include -#include #include #include #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 #include #include "hglongpressvisualizer.h" - +#include +#include 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(2,3)), + mVerticalPinchLevels(QPair(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(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(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 levels, Qt::Orientation scrollDirection) +{ + if (scrollDirection == Qt::Horizontal) { + mHorizontalPinchLevels = levels; + } else { + mVerticalPinchLevels = levels; + } +} + +QPair HgGridContainer::pinchLevels(Qt::Orientation scrollDirection) const +{ + return scrollDirection == Qt::Horizontal ? + mHorizontalPinchLevels : mVerticalPinchLevels; +} + +// End of file