ui/widgets/glxzoomwidget/src/glxzoomwidget.cpp
changeset 55 fb37077c270f
parent 49 f291796e213d
child 61 743eb0b9959e
--- a/ui/widgets/glxzoomwidget/src/glxzoomwidget.cpp	Tue Jul 06 14:16:16 2010 +0300
+++ b/ui/widgets/glxzoomwidget/src/glxzoomwidget.cpp	Wed Aug 18 09:48:53 2010 +0300
@@ -19,11 +19,17 @@
 #include <hbiconitem.h>
 #include <QTimeLine>
 #include <QGesture>
+#include <hbinstance.h>
 #include "glximagedecoderwrapper.h"
 #include "glxmodelparm.h"
 #include "glxzoomwidget.h"
 
-GlxZoomWidget::GlxZoomWidget(QGraphicsItem *parent):HbScrollArea(parent), mModel(NULL), mMinZValue(MINZVALUE), mMaxZValue(MAXZVALUE), mImageDecodeRequestSend(false), mPinchGestureOngoing(false), mDecodedImageAvailable(false), mTimerId(0)
+GlxZoomWidget::GlxZoomWidget(QGraphicsItem *parent):HbScrollArea(parent), 
+            mModel(NULL), mMinZValue(MINZVALUE), 
+            mMaxZValue(MAXZVALUE), mTimerId(0),
+            mImageDecodeRequestSend(false), 
+            mPinchGestureOngoing(false), mDecodedImageAvailable(false),
+            mZoomOngoing(false)
 {
     grabGesture(Qt::PinchGesture);
     grabGesture(Qt::TapGesture);
@@ -45,17 +51,18 @@
     //initializing the image decoder
     mImageDecoder = new GlxImageDecoderWrapper;
 
-	//inititalizing the timer for animation
-	m_AnimTimeLine = new QTimeLine(500, this);
-	m_AnimTimeLine->setFrameRange(0, 100);
-	connect(m_AnimTimeLine, SIGNAL(frameChanged(int)), this, SLOT(animationFrameChanged(int)));
-	connect(m_AnimTimeLine, SIGNAL(finished()), this, SLOT(animationTimeLineFinished()));
+	
+	//AA: signal and slot to perform double tap animation
+    //after every step redraw, signal is emitted to perform the next step
+	connect( this, SIGNAL( stepZoom() ), this, SLOT( animateDoubleTap() ), Qt::QueuedConnection );
 }
 
 GlxZoomWidget::~GlxZoomWidget()
 {
     //disconnect all existing signals
     disconnect(this,SIGNAL( pinchGestureReceived(int) ), this, SLOT( sendDecodeRequest(int) ) );
+    //AA
+    disconnect( this, SIGNAL( stepZoom() ), this, SLOT( animateDoubleTap()));
     //no Null checks required
     delete mZoomItem;
 //    delete mZoomWidget; //as this is a content widegt it will automatically be deleted
@@ -83,11 +90,30 @@
     mWindowSize = windowSize;
     mBlackBackgroundItem->setGeometry(QRectF(QPointF(0,0), mWindowSize));
     //try to reset the max and min zoomed size here
+    //In case the zoom widget is in background reset it
+    if(!mZoomOngoing && mModel) {
+        retreiveFocusedImage();
+    }
+    setZoomParams();
+}
+
+void GlxZoomWidget::forceZoomToBackground()
+{
+    mBlackBackgroundItem->hide();
+    //push the widget back to background
+    setZValue(mMinZValue);
+    mZoomOngoing = false;
+    emit zoomWidgetMovedBackground(mFocusIndex);
+    //this actually resets the ZoomWidget and decoder
+    if(mImageDecoder) {
+        mImageDecoder->resetDecoder();
+    }
+    retreiveFocusedImage();
+
 }
 
 void GlxZoomWidget::indexChanged(int index)
 {
-    Q_UNUSED(index);
     if(mFocusIndex != index) {
         mImageDecoder->resetDecoder();//reset the decoder first to cancel pending tasks
         mImageDecodeRequestSend = false;
@@ -139,7 +165,7 @@
 
 bool GlxZoomWidget::sceneEventFilter(QGraphicsItem *watched,QEvent *event)
 {
-     qDebug("GlxCoverFlow::eventFilter " );
+    qDebug( "GlxZoomWidget::sceneEventFilter enter event type %d ", event->type() );
     bool consume = false;
     if (event->type() == QEvent::Gesture) {
         consume = executeGestureEvent(watched, static_cast<QGestureEvent*>(event));
@@ -162,17 +188,21 @@
             else {
                 killTimer(mTimerId);
                 mTimerId = 0;
-                animateZoomOut(gesture->position());
+                animateZoomOut(hbInstance->allMainWindows().first()->mapToScene(gesture->position().toPoint()));
             }
         }
         event->accept(gesture);
         return true;
     }
      if (QGesture *pinch = event->gesture(Qt::PinchGesture))  {
+         if (isFocussedItemCorrupt()){
+         return true;
+         }
        QPinchGesture* pinchG = static_cast<QPinchGesture *>(pinch);
        QPinchGesture::ChangeFlags changeFlags = pinchG->changeFlags();
        if (changeFlags & QPinchGesture::ScaleFactorChanged) {
             mPinchGestureOngoing = true;
+            mZoomOngoing = true;
             //bring the zoom widget to foreground
             setZValue(mMaxZValue);
             //show the black background
@@ -184,7 +214,7 @@
             qreal value = pinchG->scaleFactor() / pinchG->lastScaleFactor();
             QPointF center = pinchG->property("centerPoint").toPointF();
             //set the gesture center to the scene coordinates
-            QPointF sceneGestureCenter = source->sceneTransform().map(center);
+            QPointF sceneGestureCenter = hbInstance->allMainWindows().first()->mapToScene(center.toPoint());
             zoomImage(value, sceneGestureCenter);
 
         }
@@ -211,6 +241,7 @@
                mBlackBackgroundItem->hide();
                //push the widget back to background
                setZValue(mMinZValue);
+               mZoomOngoing = false;
                emit zoomWidgetMovedBackground(mFocusIndex);
                //do not reset the transform here as it will then zoom-in the widget to decoded image size
            }
@@ -228,6 +259,10 @@
 
 void GlxZoomWidget::zoomImage(qreal zoomFactor, QPointF center)
 {
+        // Pinch event filtering for very small zoom factors
+    if (qAbs(1.0 - zoomFactor) < 0.007) {
+        return;
+    }
     adjustGestureCenter(center, zoomFactor);
     QSizeF requiredSize(mCurrentSize.width()*zoomFactor, mCurrentSize.height()*zoomFactor);
     limitRequiredSize(requiredSize);
@@ -259,6 +294,7 @@
 //makes sure that the gesture is on the screen center if the image is smaller than the screen
 void GlxZoomWidget::adjustGestureCenter(QPointF & gestureCenter, qreal& zoomFactor)
 {
+    /* commenting this tweak, not necessary, needs to be reimplemented for pinch: IN progress
     if(zoomFactor > 1 &&zoomFactor > 1.2 )  {
         zoomFactor = 1.2;
     }
@@ -266,6 +302,7 @@
     if(zoomFactor < 1 &&zoomFactor < 0.8 )   {
         zoomFactor = 0.8;
     }
+	*/
     QSizeF requiredSize(mCurrentSize.width()*zoomFactor, mCurrentSize.height()*zoomFactor);
     //keep smaller image centered
     if(mCurrentSize.width() <= mWindowSize.width() )
@@ -279,42 +316,49 @@
 
     }
     //maintains the boundary of the edges for zoom out conditions
-    if(zoomFactor < 1)
-    {
+    if(zoomFactor < 1) {
         QPointF itemOriginPos = mZoomWidget->sceneTransform().map(QPointF(0,0));
         bool hasWidthExceededWindow = mCurrentSize.width() > mWindowSize.width();
         bool hasHeightExceededWindow = mCurrentSize.height() > mWindowSize.height();
-        if(itemOriginPos.x() >= 0)  {
-        //image has crossed left boundry leaving blank space
-            if(hasWidthExceededWindow) {
+        if(hasWidthExceededWindow) {
+            bool hasItemCrossedBoundary = false;
+            if(itemOriginPos.x() >= -5)  {
+                //image has crossed left boundry leaving blank space
                 //stick the gesture to the left corner
                 gestureCenter.setX(itemOriginPos.x());
+                hasItemCrossedBoundary = true;
+            }
+        
+            //Check if the right boundry can be adjusted
+            if(itemOriginPos.x()+ mCurrentSize.width() <= mWindowSize.width()+5) {
+                //Image is before the right boundry leaving blank space
+                gestureCenter.setX(itemOriginPos.x()+ mCurrentSize.width() );
+                hasItemCrossedBoundary = true;
+            }
+            if((mCurrentSize.width() - mWindowSize.width() <= 20) && !hasItemCrossedBoundary) {
+                gestureCenter.setX(mWindowSize.width()/2 + (qAbs(itemOriginPos.x()) - 10));
             }
         }
-        //Check if the right boundry can be adjusted
-        if(itemOriginPos.x()+ mCurrentSize.width() <= mWindowSize.width()) {
+
+        if(hasHeightExceededWindow) {
+             bool hasItemCrossedBoundary = false;
+            //check if the upper boundry could be adjusted
+            if(itemOriginPos.y() >= -5) {
+                //image has crossed the upper boundry leaving blank space
+                //stick the image to the upper boundry
+                gestureCenter.setY(itemOriginPos.y());
+                hasItemCrossedBoundary = true;
+            }
+            //check if the lower boundry could be adjusted
+            if(itemOriginPos.y()+ mCurrentSize.height() <= mWindowSize.height()+5) {
                 //Image is before the right boundry leaving blank space
-                if(hasWidthExceededWindow) {
-                    //stick the gesture to the right corner
-                    gestureCenter.setX(itemOriginPos.x()+ mCurrentSize.width());
-                }
-        }
-        //check if the upper boundry could be adjusted
-        if(itemOriginPos.y() >= 0) {
-                //image has crossed the upper boundry leaving blank space
-                if(hasHeightExceededWindow) {
-                    //stick the image to the upper boundry
-                    gestureCenter.setY(itemOriginPos.y());
-                }
-        }
-        //check if the lower boundry could be adjusted
-        if(itemOriginPos.y()+ mCurrentSize.height() <= mWindowSize.height()) {
-        //Image is before the right boundry leaving blank space
-            if(hasHeightExceededWindow) {
                 //stick the image to the right corner
                 gestureCenter.setY(itemOriginPos.y()+ mCurrentSize.height());
+                hasItemCrossedBoundary = true;
             }
-
+            if((mCurrentSize.height() - mWindowSize.height() <= 20) && !hasItemCrossedBoundary) {
+                gestureCenter.setY(mWindowSize.height()/2 + (qAbs(itemOriginPos.y()) - 10));
+            }
         }
     }
     //control the zoom Factor to boundaries
@@ -460,48 +504,107 @@
 
 }
 
+void GlxZoomWidget::setZoomParams()
+{
+    if (mModel)  {
+        QVariant sizeVariant = mModel->data(mModel->index(mFocusIndex,0),GlxDimensionsRole);
+        QSize fsSize;
+        if(sizeVariant.isValid() &&  sizeVariant.canConvert<QSize> ()) {
+            fsSize = sizeVariant.toSize();
+            if(!(fsSize.width() < mWindowSize.width() && fsSize.height() < mWindowSize.height()))  {
+                fsSize.scale( mWindowSize, Qt::KeepAspectRatio);
+            }
+            mMaxScaleSize = fsSize;
+            mMaxScaleSize.scale(mWindowSize*13, Qt::KeepAspectRatio);
+            mMaxScaleDecSize = fsSize;
+            mMaxScaleDecSize.scale(mWindowSize*7, Qt::KeepAspectRatio);
+            mMinScaleSize = fsSize* 0.7;
+            mMinDecScaleSize = fsSize;
+        }
+    }
 
 
+}
+
 
 
 void GlxZoomWidget::animateZoomIn(QPointF animRefPoint)
 {
-      emit pinchGestureReceived(mFocusIndex);
-            //bring the zoom widget to foreground
-            setZValue(mMaxZValue);
-            //show the black background
-            mBlackBackgroundItem->setParentItem(parentItem());
-            mBlackBackgroundItem->setZValue(mMaxZValue - 1);
-            mBlackBackgroundItem->show();
-	m_AnimRefPoint = animRefPoint;
+    if (isFocussedItemCorrupt()){
+    return;
+    }
+    emit pinchGestureReceived(mFocusIndex);
+    //bring the zoom widget to foreground
+    mZoomOngoing = true;
+    setZValue(mMaxZValue);
+    //show the black background
+    mBlackBackgroundItem->setParentItem(parentItem());
+    mBlackBackgroundItem->setZValue(mMaxZValue - 1);
+    mBlackBackgroundItem->show();
+    m_AnimRefPoint = animRefPoint;
     QSizeF requiredSize = mItemSize;
-    requiredSize.scale(mWindowSize*3.5, Qt::KeepAspectRatio);
+    //MAXDTZOOMIN size is set to 3.5 times window size
+    requiredSize.scale(mWindowSize*MAXDTZOOMIN, Qt::KeepAspectRatio);
 	m_FinalAnimatedScaleFactor = requiredSize.width()/mMinDecScaleSize.width();
-	m_AnimTimeLine->setDirection(QTimeLine::Forward);
-	m_AnimTimeLine->start();
-  //  zoomImage(5, m_AnimRefPoint);
+	//initiale variable for double tap animation
+    mIncSF = 1;
+    //preserve the size when zoom out was initiated, requried for calculates applicable/req scale factor
+    //SF has to always greater than 1 for upscaling, hence range for zoomout is [1,m_FinalAnimatedScaleFactor]
+    msfInc = (m_FinalAnimatedScaleFactor-1)/NOOFSTEPS;
+    //set the no. of steps for double tap animation 
+    mdoubletapSteps = NOOFSTEPS;
+    animateDoubleTap();
 
 }
 void GlxZoomWidget::animateZoomOut(QPointF animRefPoint)
 {
-	m_AnimRefPoint = animRefPoint;
-	m_FinalAnimatedScaleFactor = mMinDecScaleSize.width()/mCurrentSize.width();
-	//m_AnimTimeLine->setDirection(QTimeLine::Backward);
-	m_AnimTimeLine->start();
+    m_AnimRefPoint = animRefPoint;
+    //Zoom out to FS (mMinDecScaleSize) from the currentsize
+    m_FinalAnimatedScaleFactor = mMinDecScaleSize.width()/mCurrentSize.width();
+    //initiale variable for double tap animation
+    mIncSF = 1;
+    //calculate the step increment SF for each step
+    msfInc = (1 - m_FinalAnimatedScaleFactor)/NOOFSTEPS;
+    //preserve the size when zoom out was initiated, requried for calculates applicable/req scale factor
+    mzoSize = mCurrentSize;
+    //set the no. of steps for double tap animation 
+    //AA:: the no.of steps are kept the same for zoomin/zoomout, however tweaking them can be considered
+    mdoubletapSteps = NOOFSTEPS;
+    animateDoubleTap();
+    //AA
+   
 }
-void GlxZoomWidget::animationFrameChanged(int frameNumber)
-{
-qreal scaleFactor = 1;
-	if(m_FinalAnimatedScaleFactor > 1) {
-        scaleFactor = (1.0 + (((m_FinalAnimatedScaleFactor - 1)/100)*frameNumber))/(mCurrentSize.width()/mMinDecScaleSize.width());
-	}
-	if(m_FinalAnimatedScaleFactor < 1) {
-        scaleFactor = (m_FinalAnimatedScaleFactor+ (((1 - m_FinalAnimatedScaleFactor)/100)*frameNumber))/(mCurrentSize.width()/mMinDecScaleSize.width());
-	}
+
 
-	zoomImage(scaleFactor, m_AnimRefPoint);
-
-}
+void GlxZoomWidget::animateDoubleTap()
+    {
+    //calculate increamental scale factor based on the step and then calculate the applicable scale factor this step
+    //increamental SF works on the ImageSize when double tap started, applicable(required) SF calculates the delate SF
+    if(m_FinalAnimatedScaleFactor > 1) {
+        //AA::zoomin case
+        mIncSF += msfInc;
+        qreal reqSF = (mItemSize.width()*(mIncSF))/mCurrentSize.width();
+        zoomImage(reqSF, m_AnimRefPoint);
+        }
+    if(m_FinalAnimatedScaleFactor < 1) {
+        //AA::zoomout case
+        mIncSF -= msfInc;
+        qreal reqSF = (mzoSize.width()* mIncSF)/mCurrentSize.width();
+        zoomImage(reqSF, m_AnimRefPoint);
+        }   
+    //check if all steps are done,if not emit signal to continue the animation
+    if(mdoubletapSteps >= 1 ){
+        mdoubletapSteps -= 1;
+        emit stepZoom();    
+        }
+    else {
+        //animation is complete, finalize the widget transform using setgeometry
+        //reset the counter
+        mdoubletapSteps = 0;
+        animationTimeLineFinished();
+        }
+        
+    }
 void GlxZoomWidget::animationTimeLineFinished()
 {
 	finalizeWidgetTransform();
@@ -510,6 +613,7 @@
                mBlackBackgroundItem->hide();
                //push the widget back to background
                setZValue(mMinZValue);
+               mZoomOngoing = false;
                emit zoomWidgetMovedBackground(mFocusIndex);
                //do not reset the transform here as it will then zoom-in the widget to decoded image size
            }
@@ -524,3 +628,13 @@
         mTimerId = 0;
     }
 }
+
+bool GlxZoomWidget::isFocussedItemCorrupt()
+{
+    QVariant variant = mModel->data( mModel->index( mFocusIndex, 0 ), GlxImageCorruptRole );
+    if ( variant.isValid() && variant.canConvert< bool> () ) {
+        return variant.value< bool > () ;
+    }
+    return false ;    
+}
+