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) : |
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); |
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 } |
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 |