ganeswidgets/src/HgContainer.cpp
changeset 2 49c70dcc3f17
parent 1 e48454f237ca
child 3 c863538fcbb6
--- a/ganeswidgets/src/HgContainer.cpp	Mon May 03 13:32:54 2010 +0300
+++ b/ganeswidgets/src/HgContainer.cpp	Fri May 14 16:57:01 2010 +0300
@@ -28,6 +28,8 @@
 #include "hgwidgetitem.h"
 #include "trace.h"
 
+//#include <hbstyleoptioncheckbox.h>
+//#include <hbcheckbox>
 #include <hbgridviewitem>
 #include <hbgridview>
 #include <hbiconitem>
@@ -50,16 +52,19 @@
     mAnimateUsingScrollBar(false),
     mSelectionMode(HgWidget::NoSelection),
     mSelectionModel(0),
-    mMarkImage(0),
+    mMarkImageOn(0),
+    mMarkImageOff(0),
     mSpringVelAtDragStart(0),
     mDragged(false),
     mFramesDragged(0),
     mHitItemView(NULL),
     mLongPressVisualizer(NULL),
     mLongPressTimer(NULL),
-    mHitItemIndex(NULL),
-    mItemSizePolicy(HgWidget::ItemSizeUserDefined),
-    mOrientation(Qt::Vertical)
+    mHitItemIndex(-1),
+    mItemSizePolicy(HgWidget::ItemSizeAutomatic),
+    mOrientation(Qt::Vertical),
+    mDelayedScrollToIndex(),
+    mIgnoreTap(false)
 {
     FUNC_LOG;
 
@@ -74,7 +79,8 @@
 
     qDeleteAll(mItems);
     mItems.clear();
-    delete mMarkImage;
+    delete mMarkImageOn;
+    delete mMarkImageOff;
     delete mRenderer;
 }
 
@@ -192,8 +198,7 @@
 {
     const QRectF containerRect(rect());
 
-    // TODO, fix logic
-    if (containerRect.height() > containerRect.width()) {
+    if (scrollDirection()== Qt::Vertical) {
         // assume we are in portrait mode, ofcource this might not be the case
         screenSize = containerRect.height()/(mRenderer->getImageSize().height() + mRenderer->getSpacing().height());
         worldSize = worldWidth();
@@ -214,9 +219,13 @@
 void HgContainer::setOrientation(Qt::Orientation orientation, bool animate)
 {
     FUNC_LOG;
-
+    
     mOrientation = orientation;
-    mRenderer->setOrientation(orientation, false);
+    mRenderer->setOrientation(orientation);
+    mRenderer->setScrollDirection(orientation, animate);
+    if (!mSpring.isActive() && mSpring.pos().x() > worldWidth())
+        boundSpring();
+
 }
 
 void HgContainer::scrollToPosition(qreal value, bool animate)
@@ -243,8 +252,67 @@
 {
     FUNC_LOG;
 
-    if (index.isValid() && mRenderer->getRowCount() > 0) {
-        scrollToPosition(QPointF(index.row()/mRenderer->getRowCount(), 0), false);
+    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;
+        }
+        
+        // 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;
+            if (scrollDirection()== Qt::Vertical) {
+                const int rowHeight = mRenderer->getImageSize().height() + mRenderer->getSpacing().height();
+                itemsOnScreen = containerRect.height()/rowHeight;
+                if ((int)containerRect.height()%rowHeight) {
+                    itemsOnScreen++;
+                }
+                itemsOnScreen *= rowCount();
+                if (itemsOnScreen + index.row() > mItems.count()) {
+                    int newItem = mItems.count()-itemsOnScreen;
+                    
+                    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);
+                }
+            } else {
+                // Scrolldirection is horizontal
+                const int rowWidth = mRenderer->getImageSize().width() + mRenderer->getSpacing().width();
+                itemsOnScreen = containerRect.width()/rowWidth;
+                if ((int)containerRect.height()%rowWidth) {
+                    itemsOnScreen++;
+                }
+                itemsOnScreen *= rowCount();
+                if (itemsOnScreen + index.row() > mItems.count()) {
+                    int newItem = mItems.count()-itemsOnScreen;
+
+                    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();            
+        } else {
+            // Coverflow case. TODO, this will need some finetuning.
+            scrollToPosition(QPointF(index.row()/mRenderer->getRowCount(), 0), false);
+            updateBySpringPosition();            
+        }                    
     }
 }
 
@@ -327,8 +395,12 @@
 int HgContainer::flags(int index) const
 {
     if (index >= 0 && index < itemCount()) {
-        if (mSelectionModel && mSelectionModel->isSelected(mSelectionModel->model()->index(index, 0))) {
-            return 1; // TODO: Assign flag to mark indicator
+        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 0;
@@ -337,7 +409,10 @@
 const HgImage *HgContainer::indicator(int flags) const
 {
     if (flags & 1) {
-        return mMarkImage;
+        return mMarkImageOn;
+    }
+    else if (flags & 2) {
+        return mMarkImageOff;
     }
 
     return 0;
@@ -363,36 +438,20 @@
 {
     Q_UNUSED(option)
     Q_UNUSED(widget)
+    
+    // update spring position at paint if needed, 
+    // this is hack for scrollbar, since dragging it 
+    // causes also paint events in here
     if (mSpring.updatePositionIfNeeded())
     {
-        // spring works always in one dimension, that is, x coord.
         qreal pos = mSpring.pos().x();
         onScrollPositionChanged(pos);
         emit scrollPositionChanged(pos, true);        
     }
-
-    QRectF vp = painter->viewport();
-    QRectF rts = mapRectToScene(drawableRect());
-    QRectF r;
-
-    // transform rectangle to vg space &
-    // rotate rendering according to orientation
-    if (mOrientation == Qt::Horizontal) {
-        r = QRectF(vp.width()-(rts.height()+rts.top()), rts.left(), rts.height(), rts.width());
-
-        mRenderer->setRect(r);
-
-        mRenderer->setCameraRotationZ(-90);
-    }
-    else {
-        r = QRectF(rts.left(), vp.height()-(rts.height()+rts.top()), rts.width(), rts.height());
-        mRenderer->setCameraRotationZ(0);
-
-        mRenderer->setRect(r);
-        
-        if (!mSpring.isActive() && mSpring.pos().x() > worldWidth())
-            boundSpring();
-    }
+    
+    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
@@ -408,8 +467,9 @@
     mRenderer->setCameraDistance(getCameraDistance(springVel));
     mRenderer->setCameraRotationY(getCameraRotationY(springVel));
     mRenderer->draw(mSpring.startPos(), mSpring.pos(), mSpring.endPos(),
-                    springVel, painter);
+                    springVel, painter, sceneTransform(), rect());
 
+    painter->setRenderHint(QPainter::SmoothPixmapTransform, false);
 }
 
 void HgContainer::resizeEvent(QGraphicsSceneResizeEvent *event)
@@ -417,12 +477,26 @@
     FUNC_LOG;
 
     HbWidget::resizeEvent(event);
+
+    if (mDelayedScrollToIndex.isValid()) {
+        scrollTo(mDelayedScrollToIndex);
+        // set scrollto index to invalid value.
+        mDelayedScrollToIndex = QModelIndex();
+    }
 }
 
 // this needs to be implemented for gesture framework to work
 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)
@@ -474,15 +548,41 @@
     if (markImage.isNull()) {
         ERROR("Failed to load :/images/mark.svg");
     }
-    mMarkImage = mQuadRenderer->createNativeImage();
-    HANDLE_ERROR_NULL(mMarkImage);
-    if (mMarkImage) {
-        mMarkImage->setImage(markImage);
+    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<HbIconItem*>(checkBox);    
+    HbStyleOptionCheckBox checkBoxOption;
+    checkBoxOption.state = QStyle::State_On;
+    style()->updatePrimitive(iconItem, HbStyle::P_CheckBox_icon, &checkBoxOption);
+    
+    if (mMarkImageOn) {
+        mMarkImageOn->setPixmap(iconItem->icon().pixmap());
+    }
+
+    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()));
     connect(&mSpring, SIGNAL(ended()), SIGNAL(scrollingEnded()));
-    connect(&mSpring, SIGNAL(started()), SIGNAL(scrollingStarted()));
+    connect(&mSpring, SIGNAL(ended()), SLOT(onScrollingEnded()));
     connect(mRenderer, SIGNAL(renderingNeeded()), SLOT(redraw()));
 
 }
@@ -533,14 +633,14 @@
     qreal delta(0);
     qreal itemSide(0);
 
-    if (mOrientation == mRenderer->getOrientation()) {
+    if (mOrientation == mRenderer->getScrollDirection()) {
         delta = gesture->delta().y();
     }
     else {
         delta = gesture->delta().x();
     }
 
-    if (mRenderer->getOrientation() == Qt::Vertical)
+    if (mRenderer->getScrollDirection() == Qt::Vertical)
         itemSide = mRenderer->getImageSize().height()+mRenderer->getSpacing().height();
     else
         itemSide = mRenderer->getImageSize().width()+mRenderer->getSpacing().width();
@@ -654,20 +754,20 @@
     // If there is content, mSelectionModel must always exist - either default or client-provided
     if (!mSelectionModel) return false;
 
-    mHitItem = getItemAt(pos, mHitItemIndex);
+    int index = -1;
+    mHitItem = getItemAt(pos, index);
     if (mHitItem)
     {
-        int index = mHitItemIndex;
-
         HgWidgetItem* item = itemByIndex(index);
         if (item && action != DoubleTap) {
             if (action == LongTap) {
                 INFO("Long tap:" << item->modelIndex().row());
+                
                 mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
-
+                
                 if (!mRenderer->coverflowModeEnabled())
-                    selectItem();
-
+                    selectItem(index);
+                
                 emit longPressed(item->modelIndex(), pos);
             }
             else if (mSelectionMode == HgWidget::MultiSelection) {
@@ -705,8 +805,7 @@
             else {
                 INFO("Tap:" << item->modelIndex().row());
 
-                if (mRenderer->coverflowModeEnabled())
-                {
+                if (mRenderer->coverflowModeEnabled()) {  //coverflow and t-bone modes  
                     if (qAbs(qreal(index) - mSpring.pos().x()) < 0.01f)
                     {
                         mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
@@ -717,11 +816,12 @@
                         mSpring.animateToPos(QPointF(index, 0));
                     }
                 }
-                else
-                {
-                    mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
-                    selectItem();
-                    emit activated(item->modelIndex());
+                else {   //grid mode
+                    if (!mIgnoreTap) {
+                        mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
+                        selectItem(index);
+                        emit activated(item->modelIndex());                        
+                    }
                 }
             }
         }
@@ -738,15 +838,7 @@
 
 bool HgContainer::getItemPoints(int index, QPolygonF& points)
 {
-    QPolygonF poly;
-    if (!mRenderer->getItemPoints(index, poly))
-        return false;
-
-    bool invertible;
-    QTransform t = qtToVgTransform().inverted(&invertible);
-
-    points = t.map(poly);
-    return true;
+    return mRenderer->getItemPoints(index, points);
 }
 
 QList<QModelIndex> HgContainer::getVisibleItemIndices() const
@@ -766,11 +858,6 @@
 {
     FUNC_LOG;
 
-    // if screen is frequently updated no need to update now.
-    if (mSpring.isActive() || mDragged ) return;
-    
-    // TODO FIX THIS FUNCTION!!!!!!!!!!!!!!!!!!!!!!
-
     int firstItemOnScreen = 0, lastItemOnScreen = 0;
     firstItemOnScreen = mSpring.pos().x();
     firstItemOnScreen *= rowCount();
@@ -784,12 +871,14 @@
     }
 }
 
-void HgContainer::selectItem()
+void HgContainer::selectItem(int index)
 {
     // TODO: replace this with own selection implementation
-    if (mHitItemIndex < 0 && mHitItemIndex >= mItems.count())
+/*    if (index < 0 && index >= mItems.count())
         return;
     
+    mHitItemIndex = index;
+    
     if (mHitItemView)
     {
         delete mHitItemView;
@@ -818,6 +907,7 @@
 
     mHitItemView->resize(mRenderer->getImageSize().width(),
         mRenderer->getImageSize().height());
+        */
 }
 
 void HgContainer::updateSelectedItem()
@@ -829,8 +919,16 @@
     if (!getItemPoints(mHitItemIndex, points))
     {
         // the item was not rendered, we must hide
-        // our qt item
+        // our qt item        
         mHitItemView->setVisible(false);
+        return;
+    }
+    
+    QRectF bounds = points.boundingRect();
+    if (!(rect().contains(bounds) || rect().intersects(bounds)))
+    {
+        mHitItemView->setVisible(false);
+        return;
     }
 
     QPolygonF img;
@@ -842,7 +940,9 @@
     QTransform t;
     QTransform::quadToQuad(img, points, t);
 
-    mHitItemView->setTransform(t);
+    //t.translate(50,50);
+    bool bOk;
+    mHitItemView->setTransform(t * this->transform().inverted(&bOk));
     mHitItemView->setVisible(true);
 }
 
@@ -883,8 +983,7 @@
 
 HgWidgetItem* HgContainer::getItemAt(const QPointF& pos, int& index)
 {
-    QPointF p = mapQtToVg(pos);
-    HgQuad* quad = mRenderer->getQuadAt(p);
+    HgQuad* quad = mRenderer->getQuadAt(pos);
     if (quad)
     {
         bool ok;
@@ -926,30 +1025,6 @@
     }
 }
 
-QTransform HgContainer::qtToVgTransform() const
-{
-    QTransform t;
-    if (mOrientation == Qt::Vertical)
-    {
-        t.translate(0, drawableRect().bottom());
-        t.scale(1, -1);
-    }
-    else // horizontal
-    {
-        t.translate(drawableRect().bottom(), 0);
-        t.scale(-1, 1);
-        t.translate(0, drawableRect().right());
-        t.rotate(-90, Qt::ZAxis);
-    }
-    return t;
-}
-
-QPointF HgContainer::mapQtToVg(const QPointF& p) const
-{
-    QTransform t = qtToVgTransform();
-    return t.map(p);
-}
-
 qreal HgContainer::getCameraDistance(qreal springVelocity)
 {
     Q_UNUSED(springVelocity)
@@ -981,17 +1056,22 @@
     Q_UNUSED(pos)
 }
 
+void HgContainer::onScrollingStarted()
+{
+    // By default do nothing
+}
+
+void HgContainer::onScrollingEnded()
+{
+    // By default do nothing
+}
+
 void HgContainer::handleCurrentChanged(const QModelIndex &current)
 {
     Q_UNUSED(current)
     // By default do nothing
 }
 
-QRectF HgContainer::drawableRect() const
-{
-    return rect();
-}
-
 void HgContainer::setDefaultImage(QImage defaultImage)
 {
     HgQuadRenderer *renderer = mRenderer->getRenderer();
@@ -1059,7 +1139,7 @@
 
 Qt::Orientation HgContainer::scrollDirection() const
 {
-    return mRenderer->getOrientation();
+    return mRenderer->getScrollDirection();
 }
 
 qreal HgContainer::scrollPosition() const