photosgallery/slideshow/engine/effectsrc/shwzoomandpaneffect.cpp
branchRCL_3
changeset 60 5b3385a43d68
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/photosgallery/slideshow/engine/effectsrc/shwzoomandpaneffect.cpp	Wed Sep 01 12:33:26 2010 +0100
@@ -0,0 +1,439 @@
+/*
+* Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    The zoom and pan effect
+ *
+*/
+
+
+
+
+//  Include Files
+#include "shwzoomandpaneffect.h"
+
+#include <glxsetvaluelayout.h>
+#include <alf/alfvisual.h>
+
+#include <alf/alfcurvepath.h>
+#include <alf/alftimedvalue.h>
+
+#include "shwresourceutility.h"
+#include "shwzoomandpanlayout.h"
+#include "shwcurvefactory.h"
+#include "shwconstants.h"
+#include "shwslideshowenginepanic.h"
+#include "shwcrossfadelayout.h"
+#include "shwtimer.h"
+#include "shwcallback.h"
+#include "shwgeometryutilities.h"
+
+#include <glxlog.h>
+
+using namespace NShwSlideshow;
+
+/**
+ * CShwZoomAndPanEffectImpl
+ * Zoom and pan dependencies
+ * This class makes our clients indepandant of the effect implementation
+ * This gives greater flexibitily in testing as the test suites can just
+ * re-implement all the methods in the real class interface without the 
+ * need to stub all our real dependencies. 
+ * If for example TShwCrossFadeLayout was a direct member of
+ * CShwZoomAndPanEffect class, all the clients would need to have access 
+ * to TShwCrossFadeLayout constructor and destructor and the test suite
+ * would need to either create a stub implementation for it or include
+ * the real class in the test (and all its dependencies)
+ *
+ * There is however no point of duplicating the whole CShwZoomAndPanEffect
+ * interface as it would mean double maintenance
+ * so we use the iImpl pointer when referencing the class members
+ */
+NONSHARABLE_CLASS( CShwZoomAndPanEffect::CShwZoomAndPanEffectImpl )
+	: public CBase
+	{
+	public:
+		
+		/**
+		 * Constructor
+		 */
+		inline CShwZoomAndPanEffectImpl();
+
+		/**
+		 * Destructor
+		 */
+		inline ~CShwZoomAndPanEffectImpl();
+
+		/**
+		 * 2nd phase constructor
+		 */
+		inline void ConstructL();
+
+	public:	// Data
+
+		/// Own: the size of the screen
+		TSize iScreenSize;
+		/// Own: the maximum thumbnail size
+		TSize iMaxThumbnailSize;
+		/// Own: the opacity layout
+		TShwCrossFadeLayout iOpacityLayout;
+		/// Own: the zoom and pan layout
+		TShwZoomAndPanLayout iZoomAndPanLayout;
+		/// Own: the pan curve
+		CAlfCurvePath* iCurve;
+		/// Own: Zoom and pan loop timer
+		CShwTimer* iLoopTimer;
+		/// Own: flag that defines if the image is large enough for zoom&pan
+		TBool iShouldZoom;
+        /// Own: Count to change the zoom direction
+        TInt iCount;
+		/// Own: the effect's info.
+		TShwEffectInfo iEffectInfo;
+
+	};
+
+// -----------------------------------------------------------------------------
+// C++ Constructor. Save a few bits of rom with inlining
+// -----------------------------------------------------------------------------
+inline CShwZoomAndPanEffect::CShwZoomAndPanEffectImpl::CShwZoomAndPanEffectImpl()
+	{
+	// CBase clears the values
+	// set layout chain
+	iOpacityLayout.SetNext( &iZoomAndPanLayout );
+	}
+
+// -----------------------------------------------------------------------------
+// Destructor. Save a few bits of rom with inlining
+// -----------------------------------------------------------------------------
+inline CShwZoomAndPanEffect::CShwZoomAndPanEffectImpl::~CShwZoomAndPanEffectImpl()
+	{
+	delete iCurve;
+	delete iLoopTimer;
+	}
+
+// -----------------------------------------------------------------------------
+// 2nd phase constructor for the implementation
+// -----------------------------------------------------------------------------
+inline void CShwZoomAndPanEffect::CShwZoomAndPanEffectImpl::ConstructL()
+    {
+    // timer for zoom and pan looping
+    iLoopTimer = CShwTimer::NewL( CActive::EPriorityStandard );
+
+    // load string for effect name, no need to cleanup stack 
+    // as no leaves between here and delete
+    HBufC* effectName = 
+        ShwResourceUtility::LocalisedNameL( R_SHW_EFFECT_ZOOM_AND_PAN );
+    if( !effectName )
+        {
+        // have to use a non-localised version
+        iEffectInfo.iName = KEffectNameZoomAndPan;
+        }
+    else
+        {
+        // set the localised version
+        iEffectInfo.iName = *effectName;
+        }
+
+    // info - uid
+    iEffectInfo.iId.iPluginUid = KDefaultEffectPluginUid;
+    iEffectInfo.iId.iIndex     = KEffectUidZoomAndPan;
+    // delete the local string
+    delete effectName;
+    }
+
+// -----------------------------------------------------------------------------
+// C++ Constructor. Save a few bits of rom with inlining
+// -----------------------------------------------------------------------------
+inline CShwZoomAndPanEffect::CShwZoomAndPanEffect()
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// NewLC. Static construction
+// -----------------------------------------------------------------------------
+CShwZoomAndPanEffect* CShwZoomAndPanEffect::NewLC()
+	{
+	CShwZoomAndPanEffect* self = new (ELeave) CShwZoomAndPanEffect;
+	CleanupStack::PushL( self );
+    
+	// create the implementation class
+    self->iImpl = new( ELeave ) CShwZoomAndPanEffectImpl;
+    // do the second phase, if it leaves impl will be deleted
+	self->iImpl->ConstructL();
+
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+CShwZoomAndPanEffect::~CShwZoomAndPanEffect()
+	{
+	delete iImpl;
+	}
+
+// -----------------------------------------------------------------------------
+// CloneLC
+// -----------------------------------------------------------------------------
+MShwEffect* CShwZoomAndPanEffect::CloneLC()
+	{
+	GLX_LOG_INFO( "CShwZoomAndPanEffect::CloneLC" );
+	// create a copy
+	CShwZoomAndPanEffect* copy = CShwZoomAndPanEffect::NewLC();
+	// transfer the member variables, only screen 
+	// size has relevant value this point
+	copy->iImpl->iScreenSize = iImpl->iScreenSize;
+	// set count to be one greater so it has a different zoom direction
+	copy->iImpl->iCount = iImpl->iCount + 1;
+    // copy the max thumbnail size
+    copy->iImpl->iMaxThumbnailSize = iImpl->iMaxThumbnailSize;
+	// return the clone
+	return copy;
+	}
+
+// -----------------------------------------------------------------------------
+// InitializeL
+// -----------------------------------------------------------------------------
+void CShwZoomAndPanEffect::InitializeL( 
+	CAlfEnv* /*aHuiEnv*/, MGlxVisualList* /*aVisualList*/,
+    MGlxMediaList* /*aMediaList*/, TSize aScreenSize )
+	{
+	GLX_LOG_INFO( "CShwZoomAndPanEffect::SetHuiEnv" );
+	// set the screen size
+	iImpl->iScreenSize = aScreenSize;
+
+    // zoom and pan wants at least triple the screen size thumbnails
+    TInt width = iImpl->iScreenSize.iWidth;
+    TInt height = iImpl->iScreenSize.iHeight;
+
+    // set the maximum thumbnail size, we need to optimize memory usage
+    // so dont load more pixels than KMaxThumbnailSize x Screen size thumbnail
+    iImpl->iMaxThumbnailSize.iWidth = width * KMaxThumbnailSize;
+	iImpl->iMaxThumbnailSize.iHeight = height * KMaxThumbnailSize;
+	}
+
+// -----------------------------------------------------------------------------
+// PrepareViewL
+// -----------------------------------------------------------------------------
+TSize CShwZoomAndPanEffect::PrepareViewL( 
+	CAlfVisual* /*aVisual*/, TSize aImageSize )
+	{
+	GLX_LOG_INFO( "CShwZoomAndPanEffect::PrepareViewL()" );
+
+    // use the namespace for coord utilities
+    using namespace NShwGeometryUtilities;
+
+    TSize originalImageSize = aImageSize;
+    // take a local copy of the size
+    TSize thumbnailSize = aImageSize;
+    // check that size was really found
+    if( ( aImageSize.iWidth == KErrNotFound )|| 
+        ( aImageSize.iHeight == KErrNotFound ) )
+        {
+        // size attribute not available so use screen size
+        thumbnailSize = iImpl->iScreenSize;
+        // need to also adjust aImageSize as its used further to make sure
+        // we dont load too big thumbnail; in this case we load screen size
+        originalImageSize = iImpl->iScreenSize;
+        }
+
+    // calculate zoom first as after that we know the real panning
+	// optimist assumes we can zoom every image
+	iImpl->iShouldZoom = ETrue;
+	// set the sizes for layout chain, return value is the zoom factor
+	TReal32 zoomFactor = 
+		iImpl->iZoomAndPanLayout.SetSizes( 
+			iImpl->iScreenSize, thumbnailSize, iImpl->iMaxThumbnailSize );
+	// if the zoomfactor is smaller than minimal desired, dont zoom&pan
+	if( zoomFactor < KMinZoomAndPanFactor )
+		{
+		iImpl->iShouldZoom = EFalse;
+		}
+    // ask for the maximum size from the layout
+    TSize maxSize = iImpl->iZoomAndPanLayout.MaximumSize();
+    // make sure we don't load the image larger than maximum size
+    thumbnailSize = maxSize;
+    // thumbnail is never loaded larger than image size, 
+    // either in image size or smaller... zooming may go past image size though
+    FitInsideBox( 
+        thumbnailSize.iWidth, thumbnailSize.iHeight,
+        originalImageSize.iWidth, originalImageSize.iHeight );
+
+	// calculate the area for the curve using the maximum size
+	// it must not cause the panning to get outside screen so need to calculate
+	// the delta box. We dont allow negative pan, 
+	// however we need to support panning only in either direction.
+    // Note that curve will have negative values, its just curve -defining 
+    // box that we make positive as negative value means too small image to pan
+    TInt curveWidth = Max( 
+        ( maxSize.iWidth - iImpl->iScreenSize.iWidth ) / 2,
+        0 );
+    TInt curveHeight = Max( 
+        ( maxSize.iHeight - iImpl->iScreenSize.iHeight ) / 2,
+        0 );
+	// delete old curve and set to NULL to prevent double delete
+	delete iImpl->iCurve;
+	iImpl->iCurve = NULL;
+	// if both are zero, dont bother creating curve
+	if( ( curveWidth > 0 ) || ( curveHeight > 0 ) )
+		{
+    	// create size
+    	TSize curvearea( curveWidth, curveHeight );
+
+		// construct new curve inside TRAP, if it fails we just dont pan
+	    TRAP_IGNORE(
+	        {
+	        CAlfCurvePath* curve = 
+	            NShwCurveFactory::CreateEllipsisL( 
+	                curvearea, KZoomAndPanCurveLength );
+	        // set new curve
+	        iImpl->iCurve = curve;
+	        } );
+		}
+
+    // return the calculated thumbnail size
+    return thumbnailSize;
+	}
+
+// -----------------------------------------------------------------------------
+// EnterViewL
+// -----------------------------------------------------------------------------
+MGlxLayout* CShwZoomAndPanEffect::EnterViewL(
+	CAlfVisual* /*aVisual*/, TInt aDuration, TInt aFadeInDuration )
+    {
+	GLX_LOG_INFO1( 
+		"CShwZoomAndPanEffect::EnterViewL( %d )", aDuration );
+
+	// calculate zoom&pan length
+	// minimum length is the view duration and transition duration * 2
+	// this is because there is transition, view and transition while
+	// this visual is visible (at least partially)
+	TInt zoom_and_pan_dur = aDuration + aFadeInDuration * 2;
+    
+	// set value, 0% -> 100%
+	iImpl->iOpacityLayout.Set( KMinOpacity );
+	iImpl->iOpacityLayout.Set( KMaxOpacity, aFadeInDuration );
+
+	// check if the image was large enough for zooming
+	if( iImpl->iShouldZoom )
+		{
+		// start with zoom in
+		TShwZoomAndPanLayout::TZoomDirection zoomdir = 
+			TShwZoomAndPanLayout::EZoomIn;
+		if( iImpl->iCount % 2 )
+			{
+			zoomdir = TShwZoomAndPanLayout::EZoomOut;
+			}
+
+		// start zoom
+		// minimum length is the view duration and transition duration * 2
+		// this is because there is transition, view and transition while
+		// this visual is visible (at least partially)
+		iImpl->iZoomAndPanLayout.StartZoom( 
+			zoomdir, zoom_and_pan_dur );
+
+		// need to start a timer to invert the zoom in case image load 
+		// takes longer than view mode lasts
+		iImpl->iLoopTimer->Start( 
+			zoom_and_pan_dur, 
+			zoom_and_pan_dur,
+			TShwCallBack< 
+				TShwZoomAndPanLayout, 
+                &TShwZoomAndPanLayout::InvertZoom >( 
+				&iImpl->iZoomAndPanLayout ) );
+		}
+	else
+		{
+		// reset the size to minimum
+		iImpl->iZoomAndPanLayout.ResetSizeToMinimum();
+		// cancel loop timer in case it is running, if not then 
+		// this is a no-op
+		iImpl->iLoopTimer->Cancel();
+		}
+	// return layout chain
+	return &iImpl->iOpacityLayout;
+    }
+
+// -----------------------------------------------------------------------------
+// ExitView
+// -----------------------------------------------------------------------------
+void CShwZoomAndPanEffect::ExitView( CAlfVisual* /*aVisual*/ )
+    {
+	GLX_LOG_INFO( "CShwZoomAndPanEffect::ExitView" );
+	// Cancel the loop timer as we are already going to the 
+	// next effect and visual
+	iImpl->iLoopTimer->Cancel();
+    }
+
+// -----------------------------------------------------------------------------
+// EnterTransitionL
+// -----------------------------------------------------------------------------
+MGlxLayout* CShwZoomAndPanEffect::EnterTransitionL(
+	CAlfVisual* /*aVisual*/, TInt aDuration )
+    {
+    GLX_LOG_INFO1( "CShwZoomAndPanEffect::EnterTransitionL( %d )", aDuration );
+
+	// increase count, so every other time we can zoom in and out but only if we 
+	// really got to transition
+	iImpl->iCount++;
+
+	// set value, drop from 100% to 0%
+    iImpl->iOpacityLayout.Set( KMaxOpacity );
+    iImpl->iOpacityLayout.Set( KMinOpacity, aDuration );
+
+	return &iImpl->iOpacityLayout;
+    }
+
+// -----------------------------------------------------------------------------
+// ExitTransition
+// -----------------------------------------------------------------------------
+void CShwZoomAndPanEffect::ExitTransition( CAlfVisual* /*aVisual*/ )
+    {
+	GLX_LOG_INFO( "CShwZoomAndPanEffect::ExitTransition" );
+    }
+
+// -----------------------------------------------------------------------------
+// PauseL
+// -----------------------------------------------------------------------------
+void CShwZoomAndPanEffect::PauseL()
+    {
+	GLX_LOG_INFO( "CShwZoomAndPanEffect::PauseL" );
+	// need to pause the layouts, start with opacity
+	iImpl->iOpacityLayout.Pause();
+	// freeze zoom and pan layout
+	iImpl->iZoomAndPanLayout.Pause();
+	// pause loop timer, it is safe to pause the timer even if its not active
+    iImpl->iLoopTimer->Pause();
+	}
+
+// -----------------------------------------------------------------------------
+// Resume
+// -----------------------------------------------------------------------------
+void CShwZoomAndPanEffect::Resume()
+    {
+	GLX_LOG_INFO( "CShwZoomAndPanEffect::Resume" );
+	// resume layouts
+	// start with opacity
+	iImpl->iOpacityLayout.Resume();
+	// resume zoom and pan layout
+	iImpl->iZoomAndPanLayout.Resume();
+	// resume loop timer
+	iImpl->iLoopTimer->Resume();
+    }
+
+// -----------------------------------------------------------------------------
+// EffectInfo.
+// -----------------------------------------------------------------------------
+TShwEffectInfo CShwZoomAndPanEffect::EffectInfo()
+	{
+	return iImpl->iEffectInfo;
+	}