17 */ |
17 */ |
18 #include <QPinchGesture> |
18 #include <QPinchGesture> |
19 #include <hbiconitem.h> |
19 #include <hbiconitem.h> |
20 #include <QTimeLine> |
20 #include <QTimeLine> |
21 #include <QGesture> |
21 #include <QGesture> |
|
22 #include <hbinstance.h> |
22 #include "glximagedecoderwrapper.h" |
23 #include "glximagedecoderwrapper.h" |
23 #include "glxmodelparm.h" |
24 #include "glxmodelparm.h" |
24 #include "glxzoomwidget.h" |
25 #include "glxzoomwidget.h" |
25 |
26 |
26 GlxZoomWidget::GlxZoomWidget(QGraphicsItem *parent):HbScrollArea(parent), mModel(NULL), mMinZValue(MINZVALUE), mMaxZValue(MAXZVALUE), mImageDecodeRequestSend(false), mPinchGestureOngoing(false), mDecodedImageAvailable(false), mTimerId(0) |
27 GlxZoomWidget::GlxZoomWidget(QGraphicsItem *parent):HbScrollArea(parent), |
|
28 mModel(NULL), mMinZValue(MINZVALUE), |
|
29 mMaxZValue(MAXZVALUE), mTimerId(0), |
|
30 mImageDecodeRequestSend(false), |
|
31 mPinchGestureOngoing(false), mDecodedImageAvailable(false), |
|
32 mZoomOngoing(false) |
27 { |
33 { |
28 grabGesture(Qt::PinchGesture); |
34 grabGesture(Qt::PinchGesture); |
29 grabGesture(Qt::TapGesture); |
35 grabGesture(Qt::TapGesture); |
30 setAcceptTouchEvents(true) ; |
36 setAcceptTouchEvents(true) ; |
31 setFrictionEnabled(false); |
37 setFrictionEnabled(false); |
43 //setBackgroundItem(mBlackBackgroundItem); |
49 //setBackgroundItem(mBlackBackgroundItem); |
44 |
50 |
45 //initializing the image decoder |
51 //initializing the image decoder |
46 mImageDecoder = new GlxImageDecoderWrapper; |
52 mImageDecoder = new GlxImageDecoderWrapper; |
47 |
53 |
48 //inititalizing the timer for animation |
54 |
49 m_AnimTimeLine = new QTimeLine(500, this); |
55 //AA: signal and slot to perform double tap animation |
50 m_AnimTimeLine->setFrameRange(0, 100); |
56 //after every step redraw, signal is emitted to perform the next step |
51 connect(m_AnimTimeLine, SIGNAL(frameChanged(int)), this, SLOT(animationFrameChanged(int))); |
57 connect( this, SIGNAL( stepZoom() ), this, SLOT( animateDoubleTap() ), Qt::QueuedConnection ); |
52 connect(m_AnimTimeLine, SIGNAL(finished()), this, SLOT(animationTimeLineFinished())); |
|
53 } |
58 } |
54 |
59 |
55 GlxZoomWidget::~GlxZoomWidget() |
60 GlxZoomWidget::~GlxZoomWidget() |
56 { |
61 { |
57 //disconnect all existing signals |
62 //disconnect all existing signals |
58 disconnect(this,SIGNAL( pinchGestureReceived(int) ), this, SLOT( sendDecodeRequest(int) ) ); |
63 disconnect(this,SIGNAL( pinchGestureReceived(int) ), this, SLOT( sendDecodeRequest(int) ) ); |
|
64 //AA |
|
65 disconnect( this, SIGNAL( stepZoom() ), this, SLOT( animateDoubleTap())); |
59 //no Null checks required |
66 //no Null checks required |
60 delete mZoomItem; |
67 delete mZoomItem; |
61 // delete mZoomWidget; //as this is a content widegt it will automatically be deleted |
68 // delete mZoomWidget; //as this is a content widegt it will automatically be deleted |
62 delete mBlackBackgroundItem; |
69 delete mBlackBackgroundItem; |
63 //reset the decoder to cancel pending tasks |
70 //reset the decoder to cancel pending tasks |
81 void GlxZoomWidget::setWindowSize(QSize windowSize) |
88 void GlxZoomWidget::setWindowSize(QSize windowSize) |
82 { |
89 { |
83 mWindowSize = windowSize; |
90 mWindowSize = windowSize; |
84 mBlackBackgroundItem->setGeometry(QRectF(QPointF(0,0), mWindowSize)); |
91 mBlackBackgroundItem->setGeometry(QRectF(QPointF(0,0), mWindowSize)); |
85 //try to reset the max and min zoomed size here |
92 //try to reset the max and min zoomed size here |
|
93 //In case the zoom widget is in background reset it |
|
94 if(!mZoomOngoing && mModel) { |
|
95 retreiveFocusedImage(); |
|
96 } |
|
97 setZoomParams(); |
|
98 } |
|
99 |
|
100 void GlxZoomWidget::forceZoomToBackground() |
|
101 { |
|
102 mBlackBackgroundItem->hide(); |
|
103 //push the widget back to background |
|
104 setZValue(mMinZValue); |
|
105 mZoomOngoing = false; |
|
106 emit zoomWidgetMovedBackground(mFocusIndex); |
|
107 //this actually resets the ZoomWidget and decoder |
|
108 if(mImageDecoder) { |
|
109 mImageDecoder->resetDecoder(); |
|
110 } |
|
111 retreiveFocusedImage(); |
|
112 |
86 } |
113 } |
87 |
114 |
88 void GlxZoomWidget::indexChanged(int index) |
115 void GlxZoomWidget::indexChanged(int index) |
89 { |
116 { |
90 Q_UNUSED(index); |
|
91 if(mFocusIndex != index) { |
117 if(mFocusIndex != index) { |
92 mImageDecoder->resetDecoder();//reset the decoder first to cancel pending tasks |
118 mImageDecoder->resetDecoder();//reset the decoder first to cancel pending tasks |
93 mImageDecodeRequestSend = false; |
119 mImageDecodeRequestSend = false; |
94 mDecodedImageAvailable = false; |
120 mDecodedImageAvailable = false; |
95 retreiveFocusedImage(); //Update mZoomItem with focused Image |
121 retreiveFocusedImage(); //Update mZoomItem with focused Image |
160 mTimerId = startTimer(500); |
186 mTimerId = startTimer(500); |
161 } |
187 } |
162 else { |
188 else { |
163 killTimer(mTimerId); |
189 killTimer(mTimerId); |
164 mTimerId = 0; |
190 mTimerId = 0; |
165 animateZoomOut(gesture->position()); |
191 animateZoomOut(hbInstance->allMainWindows().first()->mapToScene(gesture->position().toPoint())); |
166 } |
192 } |
167 } |
193 } |
168 event->accept(gesture); |
194 event->accept(gesture); |
169 return true; |
195 return true; |
170 } |
196 } |
171 if (QGesture *pinch = event->gesture(Qt::PinchGesture)) { |
197 if (QGesture *pinch = event->gesture(Qt::PinchGesture)) { |
|
198 if (isFocussedItemCorrupt()){ |
|
199 return true; |
|
200 } |
172 QPinchGesture* pinchG = static_cast<QPinchGesture *>(pinch); |
201 QPinchGesture* pinchG = static_cast<QPinchGesture *>(pinch); |
173 QPinchGesture::ChangeFlags changeFlags = pinchG->changeFlags(); |
202 QPinchGesture::ChangeFlags changeFlags = pinchG->changeFlags(); |
174 if (changeFlags & QPinchGesture::ScaleFactorChanged) { |
203 if (changeFlags & QPinchGesture::ScaleFactorChanged) { |
175 mPinchGestureOngoing = true; |
204 mPinchGestureOngoing = true; |
|
205 mZoomOngoing = true; |
176 //bring the zoom widget to foreground |
206 //bring the zoom widget to foreground |
177 setZValue(mMaxZValue); |
207 setZValue(mMaxZValue); |
178 //show the black background |
208 //show the black background |
179 mBlackBackgroundItem->setParentItem(parentItem()); |
209 mBlackBackgroundItem->setParentItem(parentItem()); |
180 mBlackBackgroundItem->setZValue(mMaxZValue - 1); |
210 mBlackBackgroundItem->setZValue(mMaxZValue - 1); |
277 { |
314 { |
278 gestureCenter.setY(mWindowSize.height()/2); |
315 gestureCenter.setY(mWindowSize.height()/2); |
279 |
316 |
280 } |
317 } |
281 //maintains the boundary of the edges for zoom out conditions |
318 //maintains the boundary of the edges for zoom out conditions |
282 if(zoomFactor < 1) |
319 if(zoomFactor < 1) { |
283 { |
|
284 QPointF itemOriginPos = mZoomWidget->sceneTransform().map(QPointF(0,0)); |
320 QPointF itemOriginPos = mZoomWidget->sceneTransform().map(QPointF(0,0)); |
285 bool hasWidthExceededWindow = mCurrentSize.width() > mWindowSize.width(); |
321 bool hasWidthExceededWindow = mCurrentSize.width() > mWindowSize.width(); |
286 bool hasHeightExceededWindow = mCurrentSize.height() > mWindowSize.height(); |
322 bool hasHeightExceededWindow = mCurrentSize.height() > mWindowSize.height(); |
287 if(itemOriginPos.x() >= 0) { |
323 if(hasWidthExceededWindow) { |
288 //image has crossed left boundry leaving blank space |
324 bool hasItemCrossedBoundary = false; |
289 if(hasWidthExceededWindow) { |
325 if(itemOriginPos.x() >= -5) { |
|
326 //image has crossed left boundry leaving blank space |
290 //stick the gesture to the left corner |
327 //stick the gesture to the left corner |
291 gestureCenter.setX(itemOriginPos.x()); |
328 gestureCenter.setX(itemOriginPos.x()); |
292 } |
329 hasItemCrossedBoundary = true; |
293 } |
330 } |
294 //Check if the right boundry can be adjusted |
331 |
295 if(itemOriginPos.x()+ mCurrentSize.width() <= mWindowSize.width()) { |
332 //Check if the right boundry can be adjusted |
|
333 if(itemOriginPos.x()+ mCurrentSize.width() <= mWindowSize.width()+5) { |
296 //Image is before the right boundry leaving blank space |
334 //Image is before the right boundry leaving blank space |
297 if(hasWidthExceededWindow) { |
335 gestureCenter.setX(itemOriginPos.x()+ mCurrentSize.width() ); |
298 //stick the gesture to the right corner |
336 hasItemCrossedBoundary = true; |
299 gestureCenter.setX(itemOriginPos.x()+ mCurrentSize.width()); |
337 } |
300 } |
338 if((mCurrentSize.width() - mWindowSize.width() <= 20) && !hasItemCrossedBoundary) { |
301 } |
339 gestureCenter.setX(mWindowSize.width()/2 + (qAbs(itemOriginPos.x()) - 10)); |
302 //check if the upper boundry could be adjusted |
340 } |
303 if(itemOriginPos.y() >= 0) { |
341 } |
|
342 |
|
343 if(hasHeightExceededWindow) { |
|
344 bool hasItemCrossedBoundary = false; |
|
345 //check if the upper boundry could be adjusted |
|
346 if(itemOriginPos.y() >= -5) { |
304 //image has crossed the upper boundry leaving blank space |
347 //image has crossed the upper boundry leaving blank space |
305 if(hasHeightExceededWindow) { |
348 //stick the image to the upper boundry |
306 //stick the image to the upper boundry |
349 gestureCenter.setY(itemOriginPos.y()); |
307 gestureCenter.setY(itemOriginPos.y()); |
350 hasItemCrossedBoundary = true; |
308 } |
351 } |
309 } |
352 //check if the lower boundry could be adjusted |
310 //check if the lower boundry could be adjusted |
353 if(itemOriginPos.y()+ mCurrentSize.height() <= mWindowSize.height()+5) { |
311 if(itemOriginPos.y()+ mCurrentSize.height() <= mWindowSize.height()) { |
354 //Image is before the right boundry leaving blank space |
312 //Image is before the right boundry leaving blank space |
|
313 if(hasHeightExceededWindow) { |
|
314 //stick the image to the right corner |
355 //stick the image to the right corner |
315 gestureCenter.setY(itemOriginPos.y()+ mCurrentSize.height()); |
356 gestureCenter.setY(itemOriginPos.y()+ mCurrentSize.height()); |
316 } |
357 hasItemCrossedBoundary = true; |
317 |
358 } |
|
359 if((mCurrentSize.height() - mWindowSize.height() <= 20) && !hasItemCrossedBoundary) { |
|
360 gestureCenter.setY(mWindowSize.height()/2 + (qAbs(itemOriginPos.y()) - 10)); |
|
361 } |
318 } |
362 } |
319 } |
363 } |
320 //control the zoom Factor to boundaries |
364 //control the zoom Factor to boundaries |
321 if(mCurrentSize.width() > mWindowSize.width() && requiredSize.width() <= mWindowSize.width()) |
365 if(mCurrentSize.width() > mWindowSize.width() && requiredSize.width() <= mWindowSize.width()) |
322 { |
366 { |
458 } |
502 } |
459 return targetPixmap; |
503 return targetPixmap; |
460 |
504 |
461 } |
505 } |
462 |
506 |
463 |
507 void GlxZoomWidget::setZoomParams() |
|
508 { |
|
509 if (mModel) { |
|
510 QVariant sizeVariant = mModel->data(mModel->index(mFocusIndex,0),GlxDimensionsRole); |
|
511 QSize fsSize; |
|
512 if(sizeVariant.isValid() && sizeVariant.canConvert<QSize> ()) { |
|
513 fsSize = sizeVariant.toSize(); |
|
514 if(!(fsSize.width() < mWindowSize.width() && fsSize.height() < mWindowSize.height())) { |
|
515 fsSize.scale( mWindowSize, Qt::KeepAspectRatio); |
|
516 } |
|
517 mMaxScaleSize = fsSize; |
|
518 mMaxScaleSize.scale(mWindowSize*13, Qt::KeepAspectRatio); |
|
519 mMaxScaleDecSize = fsSize; |
|
520 mMaxScaleDecSize.scale(mWindowSize*7, Qt::KeepAspectRatio); |
|
521 mMinScaleSize = fsSize* 0.7; |
|
522 mMinDecScaleSize = fsSize; |
|
523 } |
|
524 } |
|
525 |
|
526 |
|
527 } |
464 |
528 |
465 |
529 |
466 |
530 |
467 void GlxZoomWidget::animateZoomIn(QPointF animRefPoint) |
531 void GlxZoomWidget::animateZoomIn(QPointF animRefPoint) |
468 { |
532 { |
469 emit pinchGestureReceived(mFocusIndex); |
533 if (isFocussedItemCorrupt()){ |
470 //bring the zoom widget to foreground |
534 return; |
471 setZValue(mMaxZValue); |
535 } |
472 //show the black background |
536 emit pinchGestureReceived(mFocusIndex); |
473 mBlackBackgroundItem->setParentItem(parentItem()); |
537 //bring the zoom widget to foreground |
474 mBlackBackgroundItem->setZValue(mMaxZValue - 1); |
538 mZoomOngoing = true; |
475 mBlackBackgroundItem->show(); |
539 setZValue(mMaxZValue); |
476 m_AnimRefPoint = animRefPoint; |
540 //show the black background |
|
541 mBlackBackgroundItem->setParentItem(parentItem()); |
|
542 mBlackBackgroundItem->setZValue(mMaxZValue - 1); |
|
543 mBlackBackgroundItem->show(); |
|
544 m_AnimRefPoint = animRefPoint; |
477 QSizeF requiredSize = mItemSize; |
545 QSizeF requiredSize = mItemSize; |
478 requiredSize.scale(mWindowSize*3.5, Qt::KeepAspectRatio); |
546 //MAXDTZOOMIN size is set to 3.5 times window size |
|
547 requiredSize.scale(mWindowSize*MAXDTZOOMIN, Qt::KeepAspectRatio); |
479 m_FinalAnimatedScaleFactor = requiredSize.width()/mMinDecScaleSize.width(); |
548 m_FinalAnimatedScaleFactor = requiredSize.width()/mMinDecScaleSize.width(); |
480 m_AnimTimeLine->setDirection(QTimeLine::Forward); |
549 //initiale variable for double tap animation |
481 m_AnimTimeLine->start(); |
550 mIncSF = 1; |
482 // zoomImage(5, m_AnimRefPoint); |
551 //preserve the size when zoom out was initiated, requried for calculates applicable/req scale factor |
|
552 //SF has to always greater than 1 for upscaling, hence range for zoomout is [1,m_FinalAnimatedScaleFactor] |
|
553 msfInc = (m_FinalAnimatedScaleFactor-1)/NOOFSTEPS; |
|
554 //set the no. of steps for double tap animation |
|
555 mdoubletapSteps = NOOFSTEPS; |
|
556 animateDoubleTap(); |
483 |
557 |
484 } |
558 } |
485 void GlxZoomWidget::animateZoomOut(QPointF animRefPoint) |
559 void GlxZoomWidget::animateZoomOut(QPointF animRefPoint) |
486 { |
560 { |
487 m_AnimRefPoint = animRefPoint; |
561 m_AnimRefPoint = animRefPoint; |
488 m_FinalAnimatedScaleFactor = mMinDecScaleSize.width()/mCurrentSize.width(); |
562 //Zoom out to FS (mMinDecScaleSize) from the currentsize |
489 //m_AnimTimeLine->setDirection(QTimeLine::Backward); |
563 m_FinalAnimatedScaleFactor = mMinDecScaleSize.width()/mCurrentSize.width(); |
490 m_AnimTimeLine->start(); |
564 //initiale variable for double tap animation |
491 } |
565 mIncSF = 1; |
492 void GlxZoomWidget::animationFrameChanged(int frameNumber) |
566 //calculate the step increment SF for each step |
493 { |
567 msfInc = (1 - m_FinalAnimatedScaleFactor)/NOOFSTEPS; |
494 qreal scaleFactor = 1; |
568 //preserve the size when zoom out was initiated, requried for calculates applicable/req scale factor |
495 if(m_FinalAnimatedScaleFactor > 1) { |
569 mzoSize = mCurrentSize; |
496 scaleFactor = (1.0 + (((m_FinalAnimatedScaleFactor - 1)/100)*frameNumber))/(mCurrentSize.width()/mMinDecScaleSize.width()); |
570 //set the no. of steps for double tap animation |
497 } |
571 //AA:: the no.of steps are kept the same for zoomin/zoomout, however tweaking them can be considered |
498 if(m_FinalAnimatedScaleFactor < 1) { |
572 mdoubletapSteps = NOOFSTEPS; |
499 scaleFactor = (m_FinalAnimatedScaleFactor+ (((1 - m_FinalAnimatedScaleFactor)/100)*frameNumber))/(mCurrentSize.width()/mMinDecScaleSize.width()); |
573 animateDoubleTap(); |
500 } |
574 //AA |
501 |
575 |
502 zoomImage(scaleFactor, m_AnimRefPoint); |
576 } |
503 |
577 |
504 } |
578 |
|
579 void GlxZoomWidget::animateDoubleTap() |
|
580 { |
|
581 //calculate increamental scale factor based on the step and then calculate the applicable scale factor this step |
|
582 //increamental SF works on the ImageSize when double tap started, applicable(required) SF calculates the delate SF |
|
583 if(m_FinalAnimatedScaleFactor > 1) { |
|
584 //AA::zoomin case |
|
585 mIncSF += msfInc; |
|
586 qreal reqSF = (mItemSize.width()*(mIncSF))/mCurrentSize.width(); |
|
587 zoomImage(reqSF, m_AnimRefPoint); |
|
588 } |
|
589 if(m_FinalAnimatedScaleFactor < 1) { |
|
590 //AA::zoomout case |
|
591 mIncSF -= msfInc; |
|
592 qreal reqSF = (mzoSize.width()* mIncSF)/mCurrentSize.width(); |
|
593 zoomImage(reqSF, m_AnimRefPoint); |
|
594 } |
|
595 //check if all steps are done,if not emit signal to continue the animation |
|
596 if(mdoubletapSteps >= 1 ){ |
|
597 mdoubletapSteps -= 1; |
|
598 emit stepZoom(); |
|
599 } |
|
600 else { |
|
601 //animation is complete, finalize the widget transform using setgeometry |
|
602 //reset the counter |
|
603 mdoubletapSteps = 0; |
|
604 animationTimeLineFinished(); |
|
605 } |
|
606 |
|
607 } |
505 void GlxZoomWidget::animationTimeLineFinished() |
608 void GlxZoomWidget::animationTimeLineFinished() |
506 { |
609 { |
507 finalizeWidgetTransform(); |
610 finalizeWidgetTransform(); |
508 //push the Zoom widget to background when zoomed image size nears FS image |
611 //push the Zoom widget to background when zoomed image size nears FS image |
509 if(mStepCurrentSize.width() <= mMinDecScaleSize.width()*1.3) { |
612 if(mStepCurrentSize.width() <= mMinDecScaleSize.width()*1.3) { |
510 mBlackBackgroundItem->hide(); |
613 mBlackBackgroundItem->hide(); |
511 //push the widget back to background |
614 //push the widget back to background |
512 setZValue(mMinZValue); |
615 setZValue(mMinZValue); |
|
616 mZoomOngoing = false; |
513 emit zoomWidgetMovedBackground(mFocusIndex); |
617 emit zoomWidgetMovedBackground(mFocusIndex); |
514 //do not reset the transform here as it will then zoom-in the widget to decoded image size |
618 //do not reset the transform here as it will then zoom-in the widget to decoded image size |
515 } |
619 } |
516 } |
620 } |
517 |
621 |