ganeswidgets/src/hgcontainer.cpp
changeset 17 a10844a9914d
parent 14 645b870db620
child 20 a60f8b6b1d32
equal deleted inserted replaced
15:1ef5359bf0f4 17:a10844a9914d
    17 
    17 
    18 #include <QGesture>
    18 #include <QGesture>
    19 #include <QPainter>
    19 #include <QPainter>
    20 #include <QTimer>
    20 #include <QTimer>
    21 #include <HbMainWindow>
    21 #include <HbMainWindow>
    22 #include "hgcontainer.h"
       
    23 #include "hgmediawallrenderer.h"
       
    24 #include "hgquad.h"
       
    25 #include "hgvgquadrenderer.h"
       
    26 #include "hgvgimage.h"
       
    27 #include "hgwidgetitem.h"
       
    28 #include "trace.h"
       
    29 
       
    30 #include <HbCheckBox>
    22 #include <HbCheckBox>
    31 #include <HbGridViewItem>
    23 #include <HbGridViewItem>
    32 #include <HbGridView>
    24 #include <HbGridView>
    33 #include <HbIconItem>
    25 #include <HbIconItem>
    34 #include <QAbstractItemModel>
    26 #include <QAbstractItemModel>
    35 #include <HbTapGesture>
    27 #include <HbTapGesture>
       
    28 
       
    29 #include "hgcontainer.h"
       
    30 #include "hgmediawallrenderer.h"
       
    31 #include "hgquad.h"
       
    32 #include "hgimage.h"
       
    33 #include "hgwidgetitem.h"
       
    34 #include "trace.h"
       
    35 #include "hgquadrenderer.h"
    36 #include "hglongpressvisualizer.h"
    36 #include "hglongpressvisualizer.h"
    37 
    37 
       
    38 
    38 static const qreal KSpringKScrolling(50.0);
    39 static const qreal KSpringKScrolling(50.0);
    39 static const qreal KSpringKScrollBar(10.0);
    40 static const qreal KSpringKScrollBar(50.0);
    40 static const qreal KSpringDampingScrolling(20.0);
    41 static const qreal KSpringDampingScrolling(20.0);
    41 static const qreal KSpringDampingScrollBar(5.0);
    42 static const qreal KSpringDampingScrollBar(20.0);
    42 static const qreal KFramesToZeroVelocity(60.0);
    43 static const qreal KFramesToZeroVelocity(60.0);
    43 static const int   KLongTapDuration(400);
    44 static const int   KLongTapDuration(400);
    44 
    45 
    45 
    46 
    46 HgContainer::HgContainer(QGraphicsItem* parent) :
    47 HgContainer::HgContainer(QGraphicsItem* parent) :
   101 int HgContainer::itemCount() const
   102 int HgContainer::itemCount() const
   102 {
   103 {
   103     return mItems.count();
   104     return mItems.count();
   104 }
   105 }
   105 
   106 
   106 int HgContainer::rowCount() const
   107 int HgContainer::currentRowCount() const
   107 {
   108 {
   108     return mRenderer ? mRenderer->getRowCount() : 0;
   109     return mRenderer ? mRenderer->getRowCount() : 0;
   109 }
   110 }
   110 
   111 
   111 QList<HgWidgetItem*> HgContainer::items() const
   112 QList<HgWidgetItem*> HgContainer::items() const
   285                 const int rowHeight = mRenderer->getImageSize().height() + mRenderer->getSpacing().height();
   286                 const int rowHeight = mRenderer->getImageSize().height() + mRenderer->getSpacing().height();
   286                 itemsOnScreen = containerRect.height()/rowHeight;
   287                 itemsOnScreen = containerRect.height()/rowHeight;
   287                 if ((int)containerRect.height()%rowHeight) {
   288                 if ((int)containerRect.height()%rowHeight) {
   288                     itemsOnScreen++;
   289                     itemsOnScreen++;
   289                 }
   290                 }
   290                 itemsOnScreen *= rowCount();
   291                 itemsOnScreen *= currentRowCount();
   291                 if (itemsOnScreen + index.row() > mItems.count()) {
   292                 if (itemsOnScreen + index.row() > mItems.count()) {
   292                     int newItem = mItems.count()-itemsOnScreen;
   293                     int newItem = mItems.count()-itemsOnScreen;
   293 
   294 
   294                     if (mItems.count()%rowCount())
   295                     if (mItems.count()%currentRowCount())
   295                         newItem += rowCount() - (mItems.count()%rowCount());
   296                         newItem += currentRowCount() - (mItems.count()%currentRowCount());
   296                     if (newItem < 0)
   297                     if (newItem < 0)
   297                         newItem = 0;
   298                         newItem = 0;
   298 
   299 
   299                     scrollToPosition(QPointF(newItem/mRenderer->getRowCount(),0), false);
   300                     scrollToPosition(QPointF(newItem/mRenderer->getRowCount(),0), false);
   300                 } else {
   301                 } else {
   305                 const int rowWidth = mRenderer->getImageSize().width() + mRenderer->getSpacing().width();
   306                 const int rowWidth = mRenderer->getImageSize().width() + mRenderer->getSpacing().width();
   306                 itemsOnScreen = containerRect.width()/rowWidth;
   307                 itemsOnScreen = containerRect.width()/rowWidth;
   307                 if ((int)containerRect.height()%rowWidth) {
   308                 if ((int)containerRect.height()%rowWidth) {
   308                     itemsOnScreen++;
   309                     itemsOnScreen++;
   309                 }
   310                 }
   310                 itemsOnScreen *= rowCount();
   311                 itemsOnScreen *= currentRowCount();
   311                 if (itemsOnScreen + index.row() > mItems.count()) {
   312                 if (itemsOnScreen + index.row() > mItems.count()) {
   312                     int newItem = mItems.count()-itemsOnScreen;
   313                     int newItem = mItems.count()-itemsOnScreen;
   313 
   314 
   314                     if (mItems.count()%rowCount())
   315                     if (mItems.count()%currentRowCount())
   315                         newItem += rowCount() - (mItems.count()%rowCount());
   316                         newItem += currentRowCount() - (mItems.count()%currentRowCount());
   316                     if (newItem < 0) newItem = 0;
   317                     if (newItem < 0) newItem = 0;
   317 
   318 
   318                     scrollToPosition(QPointF(newItem/mRenderer->getRowCount(),0), false);
   319                     scrollToPosition(QPointF(newItem/mRenderer->getRowCount(),0), false);
   319                 } else {
   320                 } else {
   320                     scrollToPosition(QPointF(index.row()/mRenderer->getRowCount(), 0), false);
   321                     scrollToPosition(QPointF(index.row()/mRenderer->getRowCount(), 0), false);
   408 
   409 
   409 int HgContainer::flags(int index) const
   410 int HgContainer::flags(int index) const
   410 {
   411 {
   411     if (index >= 0 && index < itemCount()) {
   412     if (index >= 0 && index < itemCount()) {
   412         if (mSelectionMode != HgWidget::NoSelection) {
   413         if (mSelectionMode != HgWidget::NoSelection) {
   413             if (mSelectionModel && mSelectionModel->isSelected(mSelectionModel->model()->index(index, 0))) {
   414             if (mSelectionModel && 
       
   415                     mSelectionModel->model() &&
       
   416                     mSelectionModel->isSelected(mSelectionModel->model()->index(index, 0))) {
   414                 return 1; // TODO: Assign flag to mark indicator
   417                 return 1; // TODO: Assign flag to mark indicator
   415             } else
   418             } else
   416                 return 2;
   419                 return 2;
   417         }
   420         }
   418     }
   421     }
   684     }
   687     }
   685 
   688 
   686     return true;
   689     return true;
   687 }
   690 }
   688 
   691 
   689 bool HgContainer::handleTap(Qt::GestureState state, const QPointF &pos)
       
   690 {
       
   691     FUNC_LOG;
       
   692     
       
   693     bool handleGesture = false;
       
   694     
       
   695     if (hasItemAt(pos)) {
       
   696         switch (state) 
       
   697             {
       
   698             case Qt::GestureStarted:
       
   699                 {
       
   700                 if (mRenderer->coverflowModeEnabled() || !mSpring.isActive()) {
       
   701                     mIgnoreGestureAction = false;
       
   702                     
       
   703                     if (mHandleLongPress) {
       
   704                         if (mRenderer->coverflowModeEnabled()) {
       
   705                             // in coverflow mode we react to longtap only if animation is not on and
       
   706                             // center item is tapped.
       
   707                             int temp = 0;
       
   708                             if (getItemAt(pos,temp)->modelIndex() == mSelectionModel->currentIndex() &&
       
   709                                     !mSpring.isActive()) {
       
   710                                 startLongPressWatcher(pos);
       
   711                             }
       
   712                         } else {
       
   713                             startLongPressWatcher(pos);
       
   714                         }
       
   715                     }
       
   716                 } else if(mSpring.isActive()) {
       
   717                     
       
   718                     int rowCount = mRenderer->getRowCount();
       
   719                     if(rowCount != 0)   //just in case, should not be zero 
       
   720                     {
       
   721                         qreal springPos = mSpring.pos().x();
       
   722                         int gridTotalHeightInImages = ceilf( mItems.count() / rowCount );
       
   723                         qreal currentViewHeightInImages;
       
   724                         if (scrollDirection() == Qt::Horizontal ) {
       
   725                             int rowHeight = mRenderer->getImageSize().width() + mRenderer->getSpacing().width();
       
   726                             currentViewHeightInImages = rect().width() / rowHeight;
       
   727                         } else {
       
   728                             int rowHeight = mRenderer->getImageSize().height() + mRenderer->getSpacing().height();
       
   729                             currentViewHeightInImages = rect().height() / rowHeight;
       
   730                         }
       
   731                         
       
   732                         // If list does not currently fill the whole screen (some theme background behind the list
       
   733                         // is visible), and list is moving, then do not react to tapping.
       
   734                         if( springPos >= 0 
       
   735                             && springPos <= (gridTotalHeightInImages - currentViewHeightInImages) )
       
   736                         {
       
   737                             mSpring.cancel();
       
   738                         }
       
   739                     }
       
   740                     mIgnoreGestureAction = true;
       
   741                 }
       
   742                 break;
       
   743                 }
       
   744             case Qt::GestureFinished:
       
   745                 handleGesture = handleItemAction(pos, NormalTap);
       
   746             case Qt::GestureUpdated:
       
   747             case Qt::GestureCanceled:
       
   748             default:
       
   749                 stopLongPressWatcher();
       
   750                 break;
       
   751             }
       
   752         
       
   753         handleGesture = true;
       
   754     } else {
       
   755         mIgnoreGestureAction = true;
       
   756     }    
       
   757     return handleGesture;
       
   758 }
       
   759 
       
   760 bool HgContainer::handleLongTap(Qt::GestureState state, const QPointF &pos)
   692 bool HgContainer::handleLongTap(Qt::GestureState state, const QPointF &pos)
   761 {
   693 {
   762     FUNC_LOG;
   694     FUNC_LOG;
   763 
   695 
   764     bool handleGesture = false;
   696     bool handleGesture = false;
   766     if (hasItemAt(pos)) {
   698     if (hasItemAt(pos)) {
   767 
   699 
   768         switch (state) 
   700         switch (state) 
   769             {
   701             {
   770             case Qt::GestureUpdated:
   702             case Qt::GestureUpdated:
   771                 handleItemAction(pos,LongTap);
   703                 {
       
   704                 int hitItemIndex = -1;
       
   705                 HgWidgetItem* hitItem = getItemAt(pos,hitItemIndex);
       
   706                 handleLongTapAction(pos,hitItem, hitItemIndex);
       
   707                 }
   772             case Qt::GestureStarted:
   708             case Qt::GestureStarted:
   773             case Qt::GestureCanceled:
   709             case Qt::GestureCanceled:
   774             case Qt::GestureFinished:
   710             case Qt::GestureFinished:
   775             default:
   711             default:
   776                 stopLongPressWatcher();
   712                 stopLongPressWatcher();
   782     }
   718     }
   783 
   719 
   784     return handleGesture;
   720     return handleGesture;
   785 }
   721 }
   786 
   722 
   787 /*!
       
   788     Handle tap, lang tap and double tap action.
       
   789     Finds out the item in the tap position and sends out suitable signal,
       
   790     Sets the item as the current item and in multiselection mode toggles the
       
   791     item selection status.
       
   792 */
       
   793 bool HgContainer::handleItemAction(const QPointF &pos, ItemActionType action)
       
   794 {
       
   795     FUNC_LOG;
       
   796 
       
   797     // If there is content, mSelectionModel must always exist - either default or client-provided
       
   798     if (!mSelectionModel) return false;
       
   799 
       
   800     int index = -1;
       
   801     mHitItem = getItemAt(pos, index);
       
   802     if (mHitItem)
       
   803     {
       
   804         HgWidgetItem* item = itemByIndex(index);
       
   805         if (item && action != DoubleTap) {
       
   806             if (action == LongTap) {
       
   807                 INFO("Long tap:" << item->modelIndex().row());
       
   808 
       
   809                 bool currentPressed = item->modelIndex() == mSelectionModel->currentIndex();
       
   810                 
       
   811                 if (!mRenderer->coverflowModeEnabled()) {
       
   812                     selectItem(index);
       
   813                 } else {
       
   814                     mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   815                     mSpring.animateToPos(QPointF(index, 0));
       
   816                 }
       
   817 
       
   818                 if (!mIgnoreGestureAction) {
       
   819                     if (mRenderer->coverflowModeEnabled() && mHandleLongPress) {
       
   820                         if( currentPressed && !mSpring.isActive()) {
       
   821                             emit longPressed(item->modelIndex(), pos);
       
   822                         }
       
   823                     } else if (mHandleLongPress){
       
   824                         emit longPressed(item->modelIndex(), pos);
       
   825                     }
       
   826                 } else {
       
   827                     mSpring.resetVelocity();
       
   828                     update();
       
   829                     mIgnoreGestureAction = false;
       
   830                 }
       
   831             }
       
   832             else if (mSelectionMode == HgWidget::MultiSelection) {
       
   833                 mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   834                 INFO("Select:" << item->modelIndex().row());
       
   835                 mSelectionModel->select(item->modelIndex(), QItemSelectionModel::Toggle);
       
   836                 update(); // It would be enough to update the item
       
   837             }
       
   838             else if (mSelectionMode == HgWidget::SingleSelection) {
       
   839                 mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   840                 INFO("Select:" << item->modelIndex().row());
       
   841                 mSelectionModel->select(item->modelIndex(), QItemSelectionModel::ClearAndSelect);
       
   842                 update(); // It would be enough to update the item
       
   843             }
       
   844             else if (mSelectionMode == HgWidget::ContiguousSelection) {
       
   845                 mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   846                 QModelIndex newSelected = item->modelIndex();
       
   847                 QModelIndexList oldSelection = mSelectionModel->selectedIndexes();
       
   848                 INFO("Select:" << newSelected.row());
       
   849                 if (oldSelection.count() > 0 && !mSelectionModel->isSelected(newSelected)) {
       
   850                     if (newSelected.row() < oldSelection.front().row()) {
       
   851                         mSelectionModel->select(QItemSelection(newSelected, oldSelection.back()),
       
   852                             QItemSelectionModel::Select);
       
   853                     }
       
   854                     else { // newSelected.row() > oldSelection.back().row()
       
   855                         mSelectionModel->select(QItemSelection(oldSelection.front(), newSelected),
       
   856                             QItemSelectionModel::Select);
       
   857                     }
       
   858                 }
       
   859                 else {
       
   860                     mSelectionModel->select(newSelected, QItemSelectionModel::Select);
       
   861                 }
       
   862                 update(); // It would be enough to update the item
       
   863             }
       
   864             else {
       
   865                 INFO("Tap:" << item->modelIndex().row());
       
   866 
       
   867                 if (mRenderer->coverflowModeEnabled()) {  //coverflow and t-bone modes  
       
   868                     if (qAbs(qreal(index) - mSpring.pos().x()) < 0.01f)
       
   869                     {
       
   870                         mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   871                         emit activated(item->modelIndex());
       
   872                     }
       
   873                     else
       
   874                     {
       
   875                         mSpring.animateToPos(QPointF(index, 0));
       
   876                     }
       
   877                 }
       
   878                 else {   //grid mode
       
   879                     if (!mIgnoreGestureAction) {
       
   880                         // Current should be topleft item.
       
   881 //                        mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   882                         selectItem(index);
       
   883                         emit activated(item->modelIndex());                        
       
   884                     } else {
       
   885                         mSpring.resetVelocity();
       
   886                         update();
       
   887                         mIgnoreGestureAction = false;
       
   888                     }
       
   889                 }
       
   890             }
       
   891         }
       
   892 
       
   893         return true;
       
   894     }
       
   895     else {
       
   896         INFO("No quad at pos:" << pos);
       
   897 
       
   898         unselectItem();
       
   899         return false;
       
   900     }
       
   901 }
       
   902 
   723 
   903 bool HgContainer::getItemPoints(int index, QPolygonF& points)
   724 bool HgContainer::getItemPoints(int index, QPolygonF& points)
   904 {
   725 {
   905     return mRenderer->getItemPoints(index, points);
   726     return mRenderer->getItemPoints(index, points);
   906 }
   727 }
   924 {
   745 {
   925     FUNC_LOG;
   746     FUNC_LOG;
   926     
   747     
   927     int firstItemOnScreen = 0, lastItemOnScreen = 0;
   748     int firstItemOnScreen = 0, lastItemOnScreen = 0;
   928     firstItemOnScreen = mSpring.pos().x();
   749     firstItemOnScreen = mSpring.pos().x();
   929     firstItemOnScreen *= rowCount();
   750     firstItemOnScreen *= currentRowCount();
   930 
   751 
   931     int itemsOnScreen = mRenderer->getVisibleQuads().count();
   752     int itemsOnScreen = mRenderer->getVisibleQuads().count();
   932     lastItemOnScreen = firstItemOnScreen+itemsOnScreen;
   753     lastItemOnScreen = firstItemOnScreen+itemsOnScreen;
   933 
   754 
   934     if ( itemsOnScreen == 0 || (firstIndex >= firstItemOnScreen && firstIndex < lastItemOnScreen) ||
   755     if ( itemsOnScreen == 0 || (firstIndex >= firstItemOnScreen && firstIndex < lastItemOnScreen) ||
  1097 {
   918 {
  1098     Q_UNUSED(springVelocity)
   919     Q_UNUSED(springVelocity)
  1099     return 0;
   920     return 0;
  1100 }
   921 }
  1101 
   922 
  1102 void HgContainer::handleTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
   923 bool HgContainer::handleTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
  1103 {
   924 {
  1104     Q_UNUSED(pos)
   925     Q_UNUSED(pos)
  1105     Q_UNUSED(hitItem)
   926     Q_UNUSED(hitItem)
  1106     Q_UNUSED(hitItemIndex)
   927     Q_UNUSED(hitItemIndex)
  1107 }
   928     return false;
  1108 
   929 }
  1109 void HgContainer::handleLongTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
   930 
       
   931 bool HgContainer::handleLongTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
  1110 {
   932 {
  1111     Q_UNUSED(pos)
   933     Q_UNUSED(pos)
  1112     Q_UNUSED(hitItem)
   934     Q_UNUSED(hitItem)
  1113     Q_UNUSED(hitItemIndex)
   935     Q_UNUSED(hitItemIndex)
       
   936     return false;
  1114 }
   937 }
  1115 
   938 
  1116 void HgContainer::onScrollPositionChanged(qreal pos)
   939 void HgContainer::onScrollPositionChanged(qreal pos)
  1117 {
   940 {
  1118     Q_UNUSED(pos)
   941     Q_UNUSED(pos)
  1248 void HgContainer::setHandleLongPress(bool handheLongPress)
  1071 void HgContainer::setHandleLongPress(bool handheLongPress)
  1249 {
  1072 {
  1250     // this is just a flag that is used in gesturehandling logic.
  1073     // this is just a flag that is used in gesturehandling logic.
  1251     mHandleLongPress = handheLongPress;
  1074     mHandleLongPress = handheLongPress;
  1252 }
  1075 }
       
  1076 
       
  1077 bool HgContainer::handleItemSelection(HgWidgetItem* item) 
       
  1078 {
       
  1079     bool handled = true;
       
  1080     switch(mSelectionMode)
       
  1081         {
       
  1082         case HgWidget::MultiSelection: 
       
  1083             {
       
  1084             mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
  1085             INFO("Select:" << item->modelIndex().row());
       
  1086             mSelectionModel->select(item->modelIndex(), QItemSelectionModel::Toggle);
       
  1087             update(); // It would be enough to update the item
       
  1088             break;
       
  1089             }
       
  1090         case HgWidget::SingleSelection:
       
  1091             {
       
  1092             mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
  1093             INFO("Select:" << item->modelIndex().row());
       
  1094             mSelectionModel->select(item->modelIndex(), QItemSelectionModel::ClearAndSelect);
       
  1095             update(); // It would be enough to update the item
       
  1096             break;
       
  1097             }
       
  1098         case HgWidget::ContiguousSelection: 
       
  1099             {
       
  1100             mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
  1101             QModelIndex newSelected = item->modelIndex();
       
  1102             QModelIndexList oldSelection = mSelectionModel->selectedIndexes();
       
  1103             INFO("Select:" << newSelected.row());
       
  1104             if (oldSelection.count() > 0 && !mSelectionModel->isSelected(newSelected)) {
       
  1105                 if (newSelected.row() < oldSelection.front().row()) {
       
  1106                     mSelectionModel->select(QItemSelection(newSelected, oldSelection.back()),
       
  1107                         QItemSelectionModel::Select);
       
  1108                 }
       
  1109                 else { // newSelected.row() > oldSelection.back().row()
       
  1110                     mSelectionModel->select(QItemSelection(oldSelection.front(), newSelected),
       
  1111                         QItemSelectionModel::Select);
       
  1112                 }
       
  1113             }
       
  1114             else {
       
  1115                 mSelectionModel->select(newSelected, QItemSelectionModel::Select);
       
  1116             }
       
  1117             update(); // It would be enough to update the item
       
  1118             break;
       
  1119             }
       
  1120         default:
       
  1121             handled = false;
       
  1122             break;
       
  1123         }
       
  1124     
       
  1125     return handled;
       
  1126 }
       
  1127 
  1253 // EOF
  1128 // EOF