diff -r 463f1934e292 -r c348b9772569 ganeswidgets/src/HgContainer.cpp --- a/ganeswidgets/src/HgContainer.cpp Fri Jun 11 16:25:05 2010 +0100 +++ b/ganeswidgets/src/HgContainer.cpp Thu Jul 22 16:36:56 2010 +0100 @@ -18,8 +18,7 @@ #include #include #include -#include -#include +#include #include "hgcontainer.h" #include "hgmediawallrenderer.h" #include "hgquad.h" @@ -28,12 +27,12 @@ #include "hgwidgetitem.h" #include "trace.h" -//#include -//#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "hglongpressvisualizer.h" static const qreal KSpringKScrolling(50.0); @@ -64,13 +63,14 @@ mItemSizePolicy(HgWidget::ItemSizeAutomatic), mOrientation(Qt::Vertical), mDelayedScrollToIndex(), - mIgnoreTap(false) + mIgnoreGestureAction(false) { FUNC_LOG; + setFlag(QGraphicsItem::ItemHasNoContents, false); + grabGesture(Qt::PanGesture); grabGesture(Qt::TapGesture); - grabGesture(Qt::TapAndHoldGesture); } HgContainer::~HgContainer() @@ -134,24 +134,32 @@ Ownership is not transferred. Widget is redrawn to make new selection visible. */ -void HgContainer::setSelectionModel(QItemSelectionModel *selectionModel) +void HgContainer::setSelectionModel(QItemSelectionModel *selectionModel, const QModelIndex &defaultItem) { FUNC_LOG; HANDLE_ERROR_NULL(selectionModel); // Parameter is always a valid QItemSelectionModel - if (mSelectionModel != selectionModel) { - if (mSelectionModel) { // mSelectionModel is 0 when called first time - mSelectionModel->disconnect(SIGNAL(currentChanged(QModelIndex,QModelIndex)), this); + if (mSelectionModel == selectionModel) return; + + bool defaultCurrentSet(false); - if (mSelectionModel->currentIndex().isValid() && - !(selectionModel->currentIndex().isValid())) { - selectionModel->setCurrentIndex(mSelectionModel->currentIndex(), - QItemSelectionModel::Current); - } + if (!selectionModel->currentIndex().isValid()) { // If there is valid current item, do not change it + if (!mSelectionModel && defaultItem.isValid()) { // mSelectionModel is 0 when called first time + selectionModel->setCurrentIndex(defaultItem, QItemSelectionModel::Current); + defaultCurrentSet = true; + } + else if (mSelectionModel && mSelectionModel->currentIndex().isValid()) { + selectionModel->setCurrentIndex(mSelectionModel->currentIndex(), + QItemSelectionModel::Current); } - mSelectionModel = selectionModel; - connect(mSelectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - SLOT(updateByCurrentIndex(QModelIndex))); + } + + mSelectionModel = selectionModel; + + if (mSelectionModel->currentIndex().isValid() && !defaultCurrentSet) { + scrollTo(mSelectionModel->currentIndex()); + } + else { update(); } } @@ -219,13 +227,14 @@ void HgContainer::setOrientation(Qt::Orientation orientation, bool animate) { FUNC_LOG; - + mOrientation = orientation; mRenderer->setOrientation(orientation); mRenderer->setScrollDirection(orientation, animate); - if (!mSpring.isActive() && mSpring.pos().x() > worldWidth()) - boundSpring(); - + if (mSpring.isActive()) { + // Need to stop scrolling. + mSpring.cancel(); + } } void HgContainer::scrollToPosition(qreal value, bool animate) @@ -251,20 +260,22 @@ void HgContainer::scrollTo(const QModelIndex &index) { FUNC_LOG; + INFO("Scrolling to" << index); if (index.isValid() && mRenderer->getRowCount() > 0 ) { - + QRectF containerRect(rect()); if (containerRect.isNull()) { // Container hasn't been resized yet. We need to know the container // size before we can calculate if index we are scrolling to is valid. // Store scrollTo index and scrolling is performed when container is resized. mDelayedScrollToIndex = index; + return; } - + // Container has some size. We can try to calculate if scrollto index is valid. // ScrollTo index will be the top item in grid and left item on coverflow. - + if (!mRenderer->coverflowModeEnabled()) { // Grid case int itemsOnScreen = 0; @@ -277,12 +288,12 @@ itemsOnScreen *= rowCount(); if (itemsOnScreen + index.row() > mItems.count()) { int newItem = mItems.count()-itemsOnScreen; - - if (mItems.count()%rowCount()) + + if (mItems.count()%rowCount()) newItem += rowCount() - (mItems.count()%rowCount()); - if (newItem < 0) + if (newItem < 0) newItem = 0; - + scrollToPosition(QPointF(newItem/mRenderer->getRowCount(),0), false); } else { scrollToPosition(QPointF(index.row()/mRenderer->getRowCount(), 0), false); @@ -298,21 +309,21 @@ if (itemsOnScreen + index.row() > mItems.count()) { int newItem = mItems.count()-itemsOnScreen; - if (mItems.count()%rowCount()) + if (mItems.count()%rowCount()) newItem += rowCount() - (mItems.count()%rowCount()); if (newItem < 0) newItem = 0; - + scrollToPosition(QPointF(newItem/mRenderer->getRowCount(),0), false); } else { scrollToPosition(QPointF(index.row()/mRenderer->getRowCount(), 0), false); } } - updateBySpringPosition(); + updateBySpringPosition(); } else { // Coverflow case. TODO, this will need some finetuning. scrollToPosition(QPointF(index.row()/mRenderer->getRowCount(), 0), false); - updateBySpringPosition(); - } + updateBySpringPosition(); + } } } @@ -396,11 +407,10 @@ { if (index >= 0 && index < itemCount()) { if (mSelectionMode != HgWidget::NoSelection) { - // TODO, fix these returns values when we can use the checkbox indicators. if (mSelectionModel && mSelectionModel->isSelected(mSelectionModel->model()->index(index, 0))) { return 1; // TODO: Assign flag to mark indicator } else - return 0; + return 2; } } return 0; @@ -438,20 +448,20 @@ { Q_UNUSED(option) Q_UNUSED(widget) - - // update spring position at paint if needed, - // this is hack for scrollbar, since dragging it + + // update spring position at paint if needed, + // this is hack for scrollbar, since dragging it // causes also paint events in here if (mSpring.updatePositionIfNeeded()) { qreal pos = mSpring.pos().x(); onScrollPositionChanged(pos); - emit scrollPositionChanged(pos, true); + emit scrollPositionChanged(pos, true); } - + QPainter::RenderHints hints = painter->renderHints(); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); - + // interpolate spring velocity towards zero, this is done // so that spring velocity for rendering doesn't drop directly to @@ -469,7 +479,7 @@ mRenderer->draw(mSpring.startPos(), mSpring.pos(), mSpring.endPos(), springVel, painter, sceneTransform(), rect()); - painter->setRenderHint(QPainter::SmoothPixmapTransform, false); + painter->setRenderHint(QPainter::SmoothPixmapTransform, (hints.testFlag(QPainter::SmoothPixmapTransform)) ); } void HgContainer::resizeEvent(QGraphicsSceneResizeEvent *event) @@ -489,50 +499,43 @@ void HgContainer::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_UNUSED(event); - if (mSpring.isActive() && !mRenderer->coverflowModeEnabled()) { - // We could do some small animation when scrolling is stopped. - mSpring.cancel(); - update(); - mIgnoreTap = true; - } else { - mIgnoreTap = false; - } } void HgContainer::gestureEvent(QGestureEvent *event) { FUNC_LOG; + if (mItems.count() == 0) { + // we have no items so no need to handle the gesture. + event->ignore(); + return; + } + bool eventHandled(false); // Event may contain more than one gesture type - if (QGesture *gesture = event->gesture(Qt::TapAndHoldGesture)) { - QTapAndHoldGesture *tapAndHold = static_cast(gesture); - if (handleLongTap(tapAndHold->state(), - mapFromScene(event->mapToGraphicsScene(tapAndHold->position())))) { + HbTapGesture *tap = 0; + if (QGesture *gesture = event->gesture(Qt::TapGesture)) { + tap = static_cast(event->gesture(Qt::TapGesture)); + if (tap->tapStyleHint() == HbTapGesture::TapAndHold) { + eventHandled = handleLongTap(tap->state(), + mapFromScene(event->mapToGraphicsScene(tap->hotSpot()))); + + } else { + eventHandled = handleTap(tap->state(), + mapFromScene(event->mapToGraphicsScene(tap->hotSpot()))); } } - else if (QGesture *gesture = event->gesture(Qt::TapGesture)) { - // Tap and hold is not working yet in HW, tap gesture is delivered instead - QTapGesture *tap = static_cast(gesture); - eventHandled = handleTap(tap->state(), - mapFromScene(event->mapToGraphicsScene(tap->position()))); - } - else if (QGesture *pan = event->gesture(Qt::PanGesture)) { + if (QGesture *pan = event->gesture(Qt::PanGesture)) { eventHandled = handlePanning(static_cast(pan)); + } else if( mIgnoreGestureAction && tap && tap->state() == Qt::GestureCanceled ) { + // user has tapped or long pressed in grid while scrolling so we need to + // stop the 3d effect. + mSpring.resetVelocity(); + update(); + mIgnoreGestureAction = false; } - if (eventHandled) { - event->accept(); - event->accept(Qt::TapAndHoldGesture); - event->accept(Qt::TapGesture); - event->accept(Qt::PanGesture); - } - else { - event->ignore(); - event->ignore(Qt::TapAndHoldGesture); - event->ignore(Qt::TapGesture); - event->ignore(Qt::PanGesture); - } + eventHandled ? event->accept() : event->ignore(); } void HgContainer::init(Qt::Orientation scrollDirection) @@ -544,40 +547,35 @@ mQuadRenderer = mRenderer->getRenderer(); - QImage markImage(":/images/mark.svg"); - if (markImage.isNull()) { - ERROR("Failed to load :/images/mark.svg"); - } + // Fetch icons for marking mode (on and off states). + mMarkImageOn = mQuadRenderer->createNativeImage(); HANDLE_ERROR_NULL(mMarkImageOn); - if (mMarkImageOn) { - mMarkImageOn->setImage(markImage); - } - -/* mMarkImageOn = mQuadRenderer->createNativeImage(); - HANDLE_ERROR_NULL(mMarkImageOn); mMarkImageOff = mQuadRenderer->createNativeImage(); HANDLE_ERROR_NULL(mMarkImageOff); - - // Fetch icons for marking mode (on and off states). - QGraphicsItem* checkBox = style()->createPrimitive(HbStyle::P_CheckBox_icon, this); - HbIconItem* iconItem = static_cast(checkBox); - HbStyleOptionCheckBox checkBoxOption; - checkBoxOption.state = QStyle::State_On; - style()->updatePrimitive(iconItem, HbStyle::P_CheckBox_icon, &checkBoxOption); - - if (mMarkImageOn) { - mMarkImageOn->setPixmap(iconItem->icon().pixmap()); + + // Since there is no way to create the icons directly currently + // lets create HbCheckBox and ask primitives from it. + HbCheckBox* checkBox = new HbCheckBox(); + checkBox->setCheckState(Qt::Checked); + QGraphicsItem *icon = checkBox->HbWidget::primitive("icon"); + HbIconItem *iconItem = 0; + if (icon) { + iconItem = static_cast(icon); + if (mMarkImageOn) { + mMarkImageOn->setPixmap(iconItem->icon().pixmap()); + } } + checkBox->setCheckState(Qt::Unchecked); + icon = checkBox->HbWidget::primitive("icon"); + if (icon) { + iconItem = static_cast(icon); + if (mMarkImageOff) { + mMarkImageOff->setPixmap(iconItem->icon().pixmap()); + } + } + delete checkBox; - checkBoxOption.state = QStyle::State_Off; - style()->updatePrimitive(iconItem, HbStyle::P_CheckBox_icon, &checkBoxOption); - if (mMarkImageOff) { - mMarkImageOff->setPixmap(iconItem->icon().pixmap()); - } - - delete checkBox; -*/ connect(&mSpring, SIGNAL(updated()), SLOT(updateBySpringPosition())); connect(&mSpring, SIGNAL(started()), SIGNAL(scrollingStarted())); connect(&mSpring, SIGNAL(started()), SLOT(onScrollingStarted())); @@ -665,11 +663,14 @@ emit scrollingStarted(); qreal newPosition = mDrag.update(delta, pos, itemSide); - if (qAbs(newPosition - mSpring.pos().x()) > 0.01f) - { + if (qAbs(newPosition - mSpring.pos().x()) > 0.01f) { mSpring.gotoPos(QPointF(newPosition, 0)); - emit scrollPositionChanged(newPosition,true); - update(); + if (mRenderer->coverflowModeEnabled()) { + emit scrollPositionChanged(newPosition,true); + update(); + } else { + updateBySpringPosition(); + } } } } @@ -688,6 +689,12 @@ boundSpring(); } } + else if(!mDragged && gesture->state() == Qt::GestureFinished) { + if (!mRenderer->coverflowModeEnabled()) { + mSpring.resetVelocity(); + update(); + } + } else if (gesture->state() == Qt::GestureCanceled) { boundSpring(); } @@ -698,47 +705,64 @@ bool HgContainer::handleTap(Qt::GestureState state, const QPointF &pos) { FUNC_LOG; + + bool handleGesture = false; - if (state == Qt::GestureStarted) { - if (hasItemAt(pos)) { - mTapDuration.start(); - startLongPressWatcher(pos); - return true; - } - return false; - } - else if (state == Qt::GestureCanceled) - { - stopLongPressWatcher(); - - if (hasItemAt(pos)) { - return true; - } - return false; - } - else if (state == Qt::GestureFinished) { - stopLongPressWatcher(); - return handleItemAction(pos, mTapDuration.elapsed() > KLongTapDuration ? LongTap : NormalTap); - } - - return false; + if (hasItemAt(pos)) { + switch (state) + { + case Qt::GestureStarted: + { + if (mRenderer->coverflowModeEnabled() || !mSpring.isActive()) { + mIgnoreGestureAction = false; + startLongPressWatcher(pos); + } else if(mSpring.isActive()) { + mSpring.cancel(); + mIgnoreGestureAction = true; + } + break; + } + case Qt::GestureFinished: + handleGesture = handleItemAction(pos, NormalTap); + case Qt::GestureUpdated: + case Qt::GestureCanceled: + default: + stopLongPressWatcher(); + break; + } + + handleGesture = true; + } else { + mIgnoreGestureAction = true; + } + return handleGesture; } bool HgContainer::handleLongTap(Qt::GestureState state, const QPointF &pos) { FUNC_LOG; + bool handleGesture = false; + if (hasItemAt(pos)) { - mAnimateUsingScrollBar = false; - initSpringForScrolling(); - if (state == Qt::GestureFinished) { - handleItemAction(pos, LongTap); - } - return true; + switch (state) + { + case Qt::GestureUpdated: + handleItemAction(pos,LongTap); + case Qt::GestureStarted: + case Qt::GestureCanceled: + case Qt::GestureFinished: + default: + stopLongPressWatcher(); + break; + } + handleGesture = true; + } else { + mIgnoreGestureAction = true; } - return false; + return handleGesture; } /*! @@ -763,12 +787,19 @@ if (action == LongTap) { INFO("Long tap:" << item->modelIndex().row()); - mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current); - - if (!mRenderer->coverflowModeEnabled()) + if (!mRenderer->coverflowModeEnabled()) { selectItem(index); - - emit longPressed(item->modelIndex(), pos); + } else { + mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current); + } + + if (!mIgnoreGestureAction) { + emit longPressed(item->modelIndex(), pos); + } else { + mSpring.resetVelocity(); + update(); + mIgnoreGestureAction = false; + } } else if (mSelectionMode == HgWidget::MultiSelection) { mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current); @@ -817,10 +848,15 @@ } } else { //grid mode - if (!mIgnoreTap) { - mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current); + if (!mIgnoreGestureAction) { + // Current should be topleft item. +// mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current); selectItem(index); emit activated(item->modelIndex()); + } else { + mSpring.resetVelocity(); + update(); + mIgnoreGestureAction = false; } } } @@ -848,7 +884,9 @@ for (int i = 0; i < quads.count(); i++) { bool ok; int index = quads.at(i)->userData().toInt(&ok); - result.append(itemByIndex(index)->modelIndex()); + HgWidgetItem *item = itemByIndex(index); + if (item) + result.append(item->modelIndex()); } qSort(result); return result; @@ -857,7 +895,7 @@ void HgContainer::itemDataChanged(const int &firstIndex, const int &lastIndex) { FUNC_LOG; - + int firstItemOnScreen = 0, lastItemOnScreen = 0; firstItemOnScreen = mSpring.pos().x(); firstItemOnScreen *= rowCount(); @@ -865,14 +903,15 @@ int itemsOnScreen = mRenderer->getVisibleQuads().count(); lastItemOnScreen = firstItemOnScreen+itemsOnScreen; - if ((firstIndex >= firstItemOnScreen && firstIndex < lastItemOnScreen) || + if ( itemsOnScreen == 0 || (firstIndex >= firstItemOnScreen && firstIndex < lastItemOnScreen) || (lastIndex >= firstItemOnScreen && lastIndex < lastItemOnScreen)) { update(); - } + } } void HgContainer::selectItem(int index) { + Q_UNUSED(index) // TODO: replace this with own selection implementation /* if (index < 0 && index >= mItems.count()) return; @@ -966,11 +1005,6 @@ } } -void HgContainer::updateByCurrentIndex(const QModelIndex ¤t) -{ - handleCurrentChanged(current); -} - bool HgContainer::hasItemAt(const QPointF& pos) { int dummy; @@ -1066,12 +1100,6 @@ // By default do nothing } -void HgContainer::handleCurrentChanged(const QModelIndex ¤t) -{ - Q_UNUSED(current) - // By default do nothing -} - void HgContainer::setDefaultImage(QImage defaultImage) { HgQuadRenderer *renderer = mRenderer->getRenderer(); @@ -1147,3 +1175,4 @@ return mSpring.pos().x(); } +// EOF