diff -r 4ea6f81c838a -r 0e9bb658ef58 mulwidgets/mulcoverflowwidget/src/mulcoverflowcontrol.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mulwidgets/mulcoverflowwidget/src/mulcoverflowcontrol.cpp Wed Sep 01 12:23:18 2010 +0100 @@ -0,0 +1,2263 @@ +/* +* 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: Widget Control Implementation + * +*/ + + +// Include Files + +// Class Headers +#include "mulcoverflowcontrol.h" + +#include +// Alf Headers +#include +// for dosetimage func +#include +#include +#include +#include //for resource pooling +#include //for resource pooling +#include +#include + +// Mul Headers +#include +#include + + +// Gesture Helper +#include + +// Local Headers +#include "mulbaseelement.h" +#include "mulcoverflowao.h" +#include "mulcoverflowtemplate.h" +#include "mulcoverflowwidget.h" +#include "mulleave.h" //for leaving function +#include "mullog.h" //for logs +#include "mulassert.h" +#include "imulmodelaccessor.h" + +//Gesture Helper +using namespace GestureHelper; + +namespace Alf + { + +struct TMulCoverFlowControlImpl + { + TMulCoverFlowControlImpl() + { + mHighlightIndex = -1; + mScreenWidth = 0; + mScreenHeight = 0; + mGestureSpeed = 0; + mCoverFlow2DTemplate = NULL; + mIsWidgetVisible = true; //by default widget is visible . + mBaseElement = NULL; + mFastScroll = false; + mNumVisibleItem = 0; + mDefaultTextureId = -1; + mBounceInProgress = false; + mDirectionChanged = false; + mDontBounce = false; + mNumberOfRepeatEvents = 0; + mIsMirrored = false; + } + + /// @bug critical:avanhata:4/7/2008 you should never cache a property that is a property of + /// another class. The model exists to own this type of information. I gave this review comment + /// as "critical", since it is exactly these cached member variables that will + /// yield most of bugs and complexity. Refactor it away. + int mHighlightIndex; + + int mScreenWidth; + int mScreenHeight; + bool mIsWidgetVisible; + MulBaseElement* mBaseElement; + auto_ptr mCoverFlow2DTemplate; // 2D cover flow template //owns + TReal32 mGestureSpeed; + bool mFastScroll; // Flag to indicate wheher in fast scroll mode or not + int mNumVisibleItem; + int mDefaultTextureId; + bool mBounceInProgress; + int mReferencePoint; + bool mDirectionChanged; + int mCurrGestureDir; + bool mDontBounce; + int mNumberOfRepeatEvents; + bool mIsLandscape; + bool mIsMirrored; + }; + +// --------------------------------------------------------------------------- +// MulCoverFlowControl +// --------------------------------------------------------------------------- +// +MulCoverFlowControl::MulCoverFlowControl(CAlfEnv& aEnv ) + { + //Call the base class method + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::MulCoverFlowControl"); + CAlfWidgetControl::construct ( aEnv); + + mData.reset( new (EMM)TMulCoverFlowControlImpl ); + + mFeedback = MTouchFeedback::Instance(); + + if (AknLayoutUtils::LayoutMirrored()) + { + mData->mIsMirrored = true; + } + else + { + mData->mIsMirrored = false; + } + + mData->mIsLandscape = IsLandscape(); + + THROW_IF_LEAVES + ( + /// @bug critical:avanhata:30/9/2008 this is a symbian code section. don't call throwing osn code here. + /// Throwing within a TRAP is at best undefined + mCoverFlowAo.reset( new(EMM) MulCoverFlowAo( *this ) ); + + mHelper.reset(GestureHelper::CGestureHelper::NewL( *this )); + mHelper->InitAlfredPointerCaptureL( aEnv, aEnv.PrimaryDisplay(), KGroupId ); + mHelper->SetHoldingEnabled( EFalse ); + ) + } + +// --------------------------------------------------------------------------- +// ~MulCoverFlowControl +// --------------------------------------------------------------------------- +// +MulCoverFlowControl::~MulCoverFlowControl() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::~MulCoverFlowControl"); + + if( ModelAccessor() != NULL ) + { + ModelAccessor()->RemoveModelObserver(this); + } + + DestroySlider(); + + } + +// --------------------------------------------------------------------------- +// makeInterface +// --------------------------------------------------------------------------- +// +IAlfInterfaceBase* MulCoverFlowControl::makeInterface( const IfId& aType ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::makeInterface"); + UString param(aType.mImplementationId); + return CAlfWidgetControl::makeInterface( aType ); + } + +// --------------------------------------------------------------------------- +// ResetShowWidgetFlag +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::ResetShowWidgetFlag( bool aNewResetValue ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::ResetShowWidgetFlag"); + mData->mIsWidgetVisible = aNewResetValue; + if( aNewResetValue) + { + mHelper->AddObserver(this); + } + } + +// --------------------------------------------------------------------------- +// Template2D +// --------------------------------------------------------------------------- +// +MulCoverFlowTemplate* MulCoverFlowControl::Template2D() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::Template2D"); + return mData->mCoverFlow2DTemplate.get(); + } + +// --------------------------------------------------------------------------- +// IsFastScrollMode +// --------------------------------------------------------------------------- +// +bool MulCoverFlowControl::IsFastScrollMode() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::IsFastScrollMode"); + return mData->mFastScroll; + } + + +//-----------------------Event Handling API's ------------------------------- +// --------------------------------------------------------------------------- +// handleEvent +// --------------------------------------------------------------------------- +// +AlfEventStatus MulCoverFlowControl::handleEvent(const TAlfEvent& aEvent) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::handleEvent"); + if( aEvent.IsCustomEvent() ) + { + return HandleCustomEvent( aEvent ); + } + else if( aEvent.IsKeyEvent() && mData->mIsWidgetVisible ) + { + if(TotalModelCount() <= KMinNumItemForFastScroll || + aEvent.KeyEvent().iRepeats == 0 ) + { + return HandleKeyEvent( aEvent ); + } + else + { + return HandleRepeatKeyEvent( aEvent ); + } + } + else if( aEvent.IsPointerEvent() && mData->mIsWidgetVisible ) + { + MUL_LOG_INFO("MUL::MulCoverFlowControl: handleEvent ::pointer event"); + //commented as gives warning in armv5 + //THROW_IF_LEAVES + //( + TBool result = mHelper->OfferEventL(aEvent); + MUL_LOG_INFO1("MUL::MulCoverFlowControl: handleEvent::result %d ",result); + return result ? EEventConsumed :EEventNotHandled ; + // ) + } + return EEventNotHandled; + } +// --------------------------------------------------------------------------- +// HandleCustomEvent +// --------------------------------------------------------------------------- +// +AlfEventStatus MulCoverFlowControl::HandleCustomEvent( const TAlfEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleCustomEvent"); + AlfEventStatus eventConsumed = EEventNotHandled; + switch( aEvent.CustomParameter() ) + { + case ECustomEventBounceBack: + { + MUL_LOG_INFO("MUL::MulCF:Handle custom event Compensate Bounce"); + mFeedback->InstantFeedback(ETouchFeedbackBasic); + mData->mBaseElement->StopDoodling(/*3*KBounceTime*/500); + if ((TotalModelCount() > 1 && mData->mNumVisibleItem == 1) || + (TotalModelCount() > 2)) + { + Env().Send(TAlfCustomEventCommand(ECustomEventScroll, this),500/*3*KBounceTime*/ + 30); + } + else + { + //start marquee in case of text is visible. + if(mData->mBaseElement->IsTextVisibile()) + { + //start marquee after 1 sec (after doodle completed) + Env().Send(TAlfCustomEventCommand( + ECustomEventMarqueeStart, this),500/*3*KBounceTime*/ + KMarqueeTime1000); + } + // if only one item is there then no need to scroll. + mData->mBounceInProgress = false; + } + eventConsumed = EEventConsumed; + break; + } + case ECustomEventScroll: + { + MUL_LOG_INFO("MUL::MulCF:Handle custom event Compensate Bounce"); + Env().Send(TAlfCustomEventCommand(ECustomEventBounceCompleted,this),600); + + if (mData->mHighlightIndex == 0) + { + DoSetFocusIndex(TotalModelCount() -1,/*4*KBounceTime*/800); + } + else + { + DoSetFocusIndex(0,800); + } + SetSliderTickPosition(); + eventConsumed = EEventConsumed; + break; + } + case ECustomEventBounceCompleted: + { + mData->mBounceInProgress = false; + eventConsumed = EEventConsumed; + break; + } + case ECustomEventMarqueeStart: + { + mData->mBaseElement->StartMarquee(mulvisualitem::KMulTitle); + eventConsumed = EEventConsumed; + break; + } + case ECustomEventTitleMarqueeFinished: + { + mData->mBaseElement->StopMarquee(mulvisualitem::KMulTitle); + eventConsumed = EEventConsumed; + break; + } + case ECustomEventDetailMarqueeStart: + { + mData->mBaseElement->StartMarquee(mulvisualitem::KMulDetail); + eventConsumed = EEventConsumed; + break; + } + case ECustomEventMarqueeFinished: + { + mData->mBaseElement->StopMarquee(mulvisualitem::KMulDetail); + eventConsumed = EEventConsumed; + break; + } + default: break; + } + return eventConsumed; + } + +// --------------------------------------------------------------------------- +// HandleKeyEvent +// --------------------------------------------------------------------------- +// +AlfEventStatus MulCoverFlowControl::HandleKeyEvent( const TAlfEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleKeyEvent"); + AlfEventStatus eventConsumed = EEventNotHandled; + if( aEvent.Code() == EEventKey) + { + switch ( aEvent.KeyEvent().iCode ) + { + case EKeyEnter: + // Event when selection key is pressed .( key event ) + case EKeyDeviceA: + case EKeyDevice3: + { + if(aEvent.KeyEvent().iRepeats == 0) + { + if(TotalModelCount() <= 0 && mData->mBaseElement->IsEmptyText() ) + { + SetSelection(mData->mHighlightIndex); + eventConsumed = EEventConsumed; + } + else if( TotalModelCount() > 0 ) + { + SetSelection(mData->mHighlightIndex); + eventConsumed = EEventConsumed; + } + break; + } + } + case EKeyRightArrow: + { + // Send event to inform that the Right Key is pressed + if (mData->mIsMirrored) + { + HandleNavigationEvent ( EEventScrollLeft ); + } + else + { + HandleNavigationEvent ( EEventScrollRight ); + } + eventConsumed = EEventConsumed; + break; + } + + case EKeyLeftArrow: + { + // Send event to inform that the Left Key is pressed + if (mData->mIsMirrored) + { + HandleNavigationEvent ( EEventScrollRight ); + } + else + { + HandleNavigationEvent ( EEventScrollLeft ); + } + eventConsumed = EEventConsumed; + break; + } + case EKeyBackspace: + //case EKeyDelete: + { + CAlfWidgetControl::processEvent( TAlfEvent( ETypeRemove,mData->mHighlightIndex)); + eventConsumed = EEventConsumed; + break; + } + default: + { + break; + } + } + } + + else if(aEvent.Code() == EEventKeyUp) + { + mData->mNumberOfRepeatEvents = 0; + switch ( aEvent.KeyEvent().iScanCode ) + { + case EStdKeyRightArrow: + case EStdKeyLeftArrow: + { + if(mData->mFastScroll) + { + HandleEnhancedStop(); + eventConsumed = EEventConsumed; + } + break; + } + default: + { + break; + } + } + } + + return eventConsumed; + } + +// --------------------------------------------------------------------------- +// HandleRepeatKeyEvent +// --------------------------------------------------------------------------- +// +AlfEventStatus MulCoverFlowControl::HandleRepeatKeyEvent( const TAlfEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleHoldGestureEvents"); + + AlfEventStatus eventConsumed = EEventNotHandled; + if( aEvent.Code() == EEventKey) + { + switch ( aEvent.KeyEvent().iCode ) + { + case EKeyRightArrow: + { + if (mData->mIsMirrored) + { + HandleFastScrollWithKeyEvents(1); + } + else + { + HandleFastScrollWithKeyEvents(-1); + } + eventConsumed = EEventConsumed; + break; + } + + case EKeyLeftArrow: + { + if (mData->mIsMirrored) + { + HandleFastScrollWithKeyEvents(-1); + } + else + { + HandleFastScrollWithKeyEvents(1); + } + eventConsumed = EEventConsumed; + break; + } + default: + { + break; + } + } + } + return eventConsumed; + } + +// --------------------------------------------------------------------------- +// HandleFastScrollWithKeyEvents +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleFastScrollWithKeyEvents(int aDirection) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleFastScrollWithKeyEvents"); + mData->mNumberOfRepeatEvents++; + if(mData->mNumberOfRepeatEvents == 1 ) + { + CAlfWidgetControl::processEvent( TAlfEvent( ETypeFastScroll,EScrollStart )); + mData->mFastScroll = true; + mCoverFlowAo->StartMoving(1, aDirection,true,200); + } + else if(mData->mNumberOfRepeatEvents == KNumberOfRepeatsForMediumSpeed && mData->mFastScroll ) + { + mCoverFlowAo->StartMoving(1, aDirection,true,150); + } + else if(mData->mNumberOfRepeatEvents == KNumberOfRepeatsForFastSpeed && mData->mFastScroll ) + { + mCoverFlowAo->StartMoving(1, aDirection,true,100); + } + } + +// --------------------------------------------------------------------------- +// HandleNavigationEvent +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleNavigationEvent( int aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleNavigationEvent"); + + // During bounce ignore all the events + if (mData->mBounceInProgress) + { + return; + } + + int highlightIndex = mData->mHighlightIndex; + int totalcount = TotalModelCount(); + if(totalcount <= 0 && highlightIndex == -1 ) + { + return; + } + //stop marquee if the navigation is happening. + if(mData->mBaseElement->IsTextVisibile()) + { + mData->mBaseElement->StopMarquee(mulvisualitem::KMulTitle); + mData->mBaseElement->StopMarquee(mulvisualitem::KMulDetail); + } + Env().CancelCustomCommands(this); + + //Update the highlight index + switch( aEvent ) + { + case EEventScrollRight: + { + // boundary check + if( highlightIndex == totalcount - 1 ) + { + if( !mData->mBounceInProgress && !mData->mDontBounce) + { + mData->mBounceInProgress = true; + mData->mBaseElement->StartBounce(KBounceRight); + } + else + { + mData->mBounceInProgress = false; + mData->mDontBounce = false; + highlightIndex = 0; + } + } + else + { + highlightIndex++; + } + + mData->mBaseElement->SetScrollDir(EItemScrollRight); + } + break; + + case EEventScrollLeft: + { + //boundary check + if( highlightIndex == 0 ) + { + if( !mData->mBounceInProgress && !mData->mDontBounce) + { + mData->mBounceInProgress = true; + mData->mBaseElement->StartBounce(KBounceLeft); + } + else + { + mData->mBounceInProgress = false; + mData->mDontBounce = false; + highlightIndex = totalcount - 1; + } + } + else + { + highlightIndex--; + } + } + mData->mBaseElement->SetScrollDir(EItemScrollLeft); + break; + } + + // to handle bounce checks + if( !mData->mBounceInProgress ) + { + DoSetFocusIndex( highlightIndex ); + SetSliderTickPosition(); + } + } +// --------------------------------------------------------------------------- +// SendEventToBaseElement +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SendEventToBaseElement( const TAlfEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SendEventToBaseElement"); + mData->mBaseElement->offerEvent( *this, aEvent); + } + +//----------------------------Highlight and Selection API's ----------------- + +// --------------------------------------------------------------------------- +// SetHighlightIndex +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SetHighlightIndex( int aIndex, bool aUpdateSlider) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SetHighlightIndex"); + // Throw Out of Bound Exception if index is negative + __MUL_ASSERT (aIndex > -1 && aIndex < TotalModelCount(), KOutOfBound); + //set the highlight in model + if(aIndex > mData->mHighlightIndex) + { + mData->mBaseElement->SetScrollDir(EItemScrollRight); + } + else + { + mData->mBaseElement->SetScrollDir(EItemScrollLeft); + } + DoSetFocusIndex( aIndex ); + if (aUpdateSlider) + { + SetSliderTickPosition(); + } + } +// --------------------------------------------------------------------------- +// DoSetFocusIndex +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::DoSetFocusIndex( int aNewIndex, int aAnimationTime ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::DoSetFocusIndex"); + + if(aNewIndex < 0 ) + { + return; + } + + int oldindex = mData->mHighlightIndex; + IMulModelAccessor* accessor = static_cast(widget()->model()); + if(accessor) + { + if( oldindex == aNewIndex ) + { + accessor->SetHighlight( aNewIndex ); + + // When one item case to cancel the drag effect + mData->mBaseElement->StopDoodling(200); + return; + } + // handling of cancelling bounce in 2 items case + if(TotalModelCount() == 2) + { + if((mData->mBaseElement->ScrollDir() == EItemScrollRight && aNewIndex == 1 && oldindex == 2)|| + (mData->mBaseElement->ScrollDir() == EItemScrollLeft && aNewIndex == 2 && oldindex == 1)) + { + mData->mBaseElement->StopDoodling(200); + return; + } + } + + accessor->SetHighlight( aNewIndex ); + accessor->ScrollWindow( WindowTop(aNewIndex) ); + + // Set the new focused item + mData->mHighlightIndex = aNewIndex; + + // Throw Out of Bound Exception if index is negative + __MUL_ASSERT( mData->mHighlightIndex > -1 , KOutOfBound ); + mData->mBaseElement->offerEvent(*this,TAlfEvent(ETypeHighlight,aAnimationTime)); + + if( mData->mIsWidgetVisible ) + { + // If the widget is in hidden mode no event will be sent to the application/client + CAlfWidgetControl::processEvent( TAlfEvent( ETypeHighlight,mData->mHighlightIndex)); + } + } + } + +// ---------------------------------------------------------------------------- +// SetSelection +// ---------------------------------------------------------------------------- +// +void MulCoverFlowControl::SetSelection(int aHighlight) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SetSelection"); + CAlfWidgetControl::processEvent ( TAlfEvent ( ETypeSelect, aHighlight)); + } + +// --------------------------------------------------------------------------- +// HighlightIndex +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::HighlightIndex() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HighlightIndex"); + return mData->mHighlightIndex; + } + +// --------------------------------------------------------------------------- +// SetSliderTickPosition +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SetSliderTickPosition( ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SetSliderTickPosition"); + if (mData->mCoverFlow2DTemplate->IsSliderVisible()) + { + IMulSliderModel* mulSliderModel = GetSliderModel(); + if( mulSliderModel && mData->mHighlightIndex >= KInitialvalueZero ) + { + mulSliderModel->SetPrimaryValue( mData->mHighlightIndex ); + } + } + } + +//----------------------Model Change Related API's---------------------------- +// ---------------------------------------------------------------------------- +// ModelStateChanged +// ---------------------------------------------------------------------------- +// +void MulCoverFlowControl::ModelStateChanged( TMulChangedState aState, IMulVariantType& aData ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::ModelStateChanged"); + switch( aState ) + { + case EItemUpdated: + { + int index = aData.integer(); + if(TotalModelCount() < 2*mData->mNumVisibleItem+1) + { + HandleLessItemsUpdate(index); + } + else + { + int relativeIndex = 0; + if (IsIndexInVisibleWindow(index, relativeIndex)) + { + UpdateCoverflowItem(index,relativeIndex); + mData->mBaseElement->CancelRotationOnUpdate(relativeIndex); + } + } + break; + } + case EHighlightChanged: + { + if (mData->mHighlightIndex != aData.integer()) + { + mData->mHighlightIndex = aData.integer(); + IMulModelAccessor* accessor = static_cast(widget()->model()); + if( mData->mHighlightIndex == 0 ) + { + mData->mBaseElement->ShowEmptyText(false); + } + if( mData->mHighlightIndex >= 0) + { + // the same things have to be done for highlight>0 and highlight = 0 + // the only diff is at highlight 0 dont show empty text + accessor->ScrollWindow(WindowTop(mData->mHighlightIndex)); + mData->mBaseElement->UpdateVisuals(); + mData->mBaseElement->SetCounterText(); + SetSliderTickPosition(); + } + else + { + // remove the visualisation and hide counter. + mData->mBaseElement->RecycleIconVisuals(); + mData->mBaseElement->ShowEmptyText( true ); + } + } + break; + } + case EItemsInserted: + { + HandleModelCountChange(); + break; + } + case EItemsRemoved: + { + HandleModelCountChange(); + CAlfWidgetControl::processEvent( TAlfEvent( ETypeItemRemoved )); + break; + } + + } + } + +// --------------------------------------------------------------------------- +// HandleLessItemsUpdate +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleLessItemsUpdate(int aIndex) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleLessItemsUpdate"); + + int highlight = mData->mHighlightIndex; + IMulModelAccessor* accessor = static_cast(widget()->model()); + if(accessor) + { + highlight = accessor->Highlight(); + } + + if(aIndex == highlight) + { + UpdateCoverflowItem(aIndex,mData->mNumVisibleItem); + if(mData->mNumVisibleItem != 1 && TotalModelCount() == 3) + { + UpdateCoverflowItem(aIndex,mData->mNumVisibleItem + 3); + UpdateCoverflowItem(aIndex,mData->mNumVisibleItem - 3); + } + } + else + { + // fulscreen tempalte and 2d in portrait + if(mData->mNumVisibleItem == 1) + { + UpdateCoverflowItem(aIndex,mData->mNumVisibleItem+1); + UpdateCoverflowItem(aIndex,mData->mNumVisibleItem-1); + } + else + { + // 2d template landscape mode + if(TotalModelCount() == 2) + { + UpdateCoverflowItem(aIndex,mData->mNumVisibleItem+(aIndex - highlight)); + } + else + { + int relativeIndex = (aIndex - highlight) + mData->mNumVisibleItem; + if(relativeIndex >= 0 && relativeIndex < 2*mData->mNumVisibleItem+1) + { + UpdateCoverflowItem(aIndex,relativeIndex); + } + relativeIndex = relativeIndex + TotalModelCount(); + if(relativeIndex >= 0 && relativeIndex < 2*mData->mNumVisibleItem+1) + { + UpdateCoverflowItem(aIndex,relativeIndex); + } + + relativeIndex = mData->mNumVisibleItem - (TotalModelCount() - aIndex + highlight); + if(relativeIndex >= 0 && relativeIndex < 2*mData->mNumVisibleItem+1) + { + UpdateCoverflowItem(aIndex,relativeIndex); + } + relativeIndex = relativeIndex - TotalModelCount(); + if(relativeIndex >= 0 && relativeIndex < 2*mData->mNumVisibleItem+1) + { + UpdateCoverflowItem(aIndex,relativeIndex); + } + } + } + } + } + +// --------------------------------------------------------------------------- +// IsIndexInVisibleWindow +// --------------------------------------------------------------------------- +// +bool MulCoverFlowControl::IsIndexInVisibleWindow(const int aIndex, int& aRelativeIndex) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::IsIndexInVisibleWindow"); + + int totalVisual = TotalModelCount(); + int noOfVisuals = mData->mNumVisibleItem; + int highlightRelativeIndex = mData->mNumVisibleItem; + int highlight = mData->mHighlightIndex; + IMulModelAccessor* accessor = static_cast(widget()->model()); + if(accessor) + { + highlight = accessor->Highlight(); + } + + int leftIndex = highlight - noOfVisuals; + int rightIndex = highlight + noOfVisuals; + + if (leftIndex >= 0) + { + if ((aIndex <= highlight) && (aIndex >= leftIndex)) + { + aRelativeIndex = highlightRelativeIndex - (highlight - aIndex); + return true; + } + } + else + { + if (aIndex <= highlight) + { + aRelativeIndex = highlightRelativeIndex - (highlight - aIndex); + return true; + } + else + { + leftIndex = totalVisual + leftIndex ; + if (aIndex >= leftIndex) + { + aRelativeIndex = highlightRelativeIndex - noOfVisuals + (aIndex - leftIndex); + return true; + } + } + } + + if (rightIndex < totalVisual) + { + if ((aIndex >= highlight) && (aIndex <= rightIndex)) + { + aRelativeIndex = highlightRelativeIndex + (aIndex - highlight); + return true; + } + } + else + { + if (aIndex >= highlight) + { + aRelativeIndex = highlightRelativeIndex + (aIndex - highlight); + return true; + } + rightIndex = rightIndex - totalVisual; + if (aIndex <= rightIndex) + { + aRelativeIndex = highlightRelativeIndex + noOfVisuals - (rightIndex - aIndex); + return true; + } + } + + return false; + } + + +// --------------------------------------------------------------------------- +// RelativeToAbsolute +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::RelativeToAbsolute(const int aRelativeIndex) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::RelativeToAbsolute"); + int highlightRelativeIndex = mData->mNumVisibleItem; + int absolute = -1; + int totalVisuals = TotalModelCount(); + + int highlight = mData->mHighlightIndex; + IMulModelAccessor* accessor = static_cast(widget()->model()); + if(accessor) + { + highlight = accessor->Highlight(); + } + + if(totalVisuals <= 0) + { + // absolute index is always -1, so no need of any calculations + } + else if(totalVisuals < 2*mData->mNumVisibleItem + 1) + { + if(aRelativeIndex == highlightRelativeIndex) + { + absolute = highlight; + } + else + { + if(mData->mNumVisibleItem == 1) + { + if (totalVisuals == 1) + { + absolute = -1; + } + else if(totalVisuals == 2) + { + absolute = highlight + 1; + absolute = absolute >= totalVisuals ? 0 : absolute; + } + } + else + { + if (totalVisuals == 1) + { + absolute = -1; + } + else if(totalVisuals == 2) + { + absolute = highlight + (aRelativeIndex - highlightRelativeIndex); + absolute = absolute >= totalVisuals ? -1 : absolute; + } + else // totalvisuals > 3 + { + if(aRelativeIndex - highlightRelativeIndex > 0) + { + absolute = highlight + aRelativeIndex - highlightRelativeIndex; + } + else + { + absolute = highlight + aRelativeIndex - highlightRelativeIndex + + TotalModelCount(); + } + absolute = absolute >= totalVisuals ? absolute - totalVisuals : absolute; + } + } + } + } + else + { + if(aRelativeIndex == highlightRelativeIndex) + { + absolute = highlight; + } + else if (aRelativeIndex > highlightRelativeIndex) + { + absolute = highlight + (aRelativeIndex - highlightRelativeIndex); + absolute = absolute >= totalVisuals ? (absolute - totalVisuals) : absolute; + } + else + { + absolute = highlight - (highlightRelativeIndex - aRelativeIndex); + absolute = absolute <0 ? (totalVisuals + absolute) : absolute; + absolute = absolute > totalVisuals - 1 ? -1 : absolute; + } + } + return absolute; + } + + +// --------------------------------------------------------------------------- +// TotalModelCount +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::TotalModelCount() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::TotalModelCount"); + + IMulModelAccessor* accessor = static_cast(widget()->model()); + if(accessor) + { + return accessor->CurrentItemCount(); + } + return -1; + } + +// --------------------------------------------------------------------------- +// HandleModelCountChange +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleModelCountChange() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleModelCountChange"); + IMulModelAccessor* accessor = static_cast(widget()->model()); + if(accessor) + { + if(TotalModelCount() < (2*mData->mNumVisibleItem + 1)) + { + mData->mBaseElement->UpdateVisuals(); + } + mData->mBaseElement->UpdateSliderTick( TotalModelCount() ); + mData->mBaseElement->SetCounterText(); + } + } + +// --------------------------------------------------------------------------- +// modelAccessor +// --------------------------------------------------------------------------- +// +IMulModelAccessor* MulCoverFlowControl::ModelAccessor() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::ModelAccessor"); + if(widget()) + { + return static_cast(widget()->model()); + } + return NULL; + } + +// --------------------------------------------------------------------------- +// ModelChanged +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::ModelChanged( IMulModelAccessor* aAccessor ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::ModelChanged"); + Env().CancelCustomCommands(this); + // update the highlight index as well as the no of item. + mData->mHighlightIndex = aAccessor->Highlight(); + + CAlfLayout* main = (CAlfLayout*) mData->mBaseElement->findVisual( KMainLayoutIndex ); + TSize mainSize = main->Size().Target().AsSize(); + int width = mainSize.iWidth; + int height = mainSize.iHeight; + + if( width == 0 && height == 0 ) + { + return; + } + else + { + // @todo check if we are setting a new model with the same old template, + // then should we call CreateTemplateElement + mData->mScreenWidth = width; + mData->mScreenHeight = height; + CreateTemplateElement(aAccessor->Template()); + mData->mBaseElement->CreateAndInitializeVisuals(); + aAccessor->SetVisibleWindow( 2 * mData->mCoverFlow2DTemplate->MaxVisibleCount() + 1 + ,WindowTop(mData->mHighlightIndex)); + // For setting or clearing empty text if depending on the new modle count + SendEventToBaseElement( TAlfEvent( EEventWidgetInitialized ) ); + } + } + + + +//-----------------Template Element Creation API's -------------------------- + +// --------------------------------------------------------------------------- +// CreateTemplateElement +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::CreateTemplateElement( mulwidget::TLogicalTemplate aTemplateName) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::CreateTemplateElement"); + if (aTemplateName == mulwidget::KTemplate1) + { + mData->mCoverFlow2DTemplate.reset( new(EMM) MulCoverFlowTemplate1(*this, *mData->mBaseElement)); + } + else if(aTemplateName == mulwidget::KTemplate4) + { + mData->mCoverFlow2DTemplate.reset( new(EMM) MulCoverFlowTemplate4(*this, *mData->mBaseElement)); + } + else + { + // Invalid template + return; + } + mData->mCoverFlow2DTemplate->CreateVisualisation(IsLandscape()); + // set holding mode to gesture helper. + SetHoldingEnabled(); + } + + + +//--------------Orientation Change Related API's----------------------------- +// --------------------------------------------------------------------------- +// VisualLayoutUpdated +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::VisualLayoutUpdated (CAlfVisual& aVisual) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::VisualLayoutUpdated"); + + TSize topLayoutSize = aVisual.Size().Target().AsSize(); ; + int height = topLayoutSize.iHeight; + int width = topLayoutSize.iWidth; + + // to avoid unnecessary visual layout updated calls . + // in order to check if the orientation has changed really or not this is done . + if( mData->mScreenWidth == width && height == mData->mScreenHeight ) + { + return; + } + + mData->mScreenWidth = width; + mData->mScreenHeight = height; + + + IMulModelAccessor* accessor = ModelAccessor(); + if(IsLandscape() == mData->mIsLandscape) + { + if(accessor) + { + CreateTemplateElement(accessor->Template()); + mData->mBaseElement->CreateAndInitializeVisuals(); + accessor->SetVisibleWindow( 2 * mData->mCoverFlow2DTemplate->MaxVisibleCount() + 1 + ,WindowTop(mData->mHighlightIndex)); + // For setting or clearing empty text if depending on the new modle count + SendEventToBaseElement( TAlfEvent( EEventWidgetInitialized ) ); + } + else + { + // For null model + // reset the coverflow 2d template to NULL + mData->mCoverFlow2DTemplate.reset(NULL); + } + } + else + { + mData->mIsLandscape = IsLandscape(); + + if(!accessor) + { + mData->mBaseElement->SetDefaultSize(TSize(mData->mScreenWidth,mData->mScreenHeight)); + return; + } + + mData->mBaseElement->OrientationChange(); + // enable or disable hold events depending on whether ECF enabled + SetHoldingEnabled(); + } + + } + +// --------------------------------------------------------------------------- +// RecycleVisuals +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::RecycleVisuals() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::RecycleVisuals"); + // reset the coverflow 2d template to NULL + mData->mCoverFlow2DTemplate.reset(NULL); + + if(mData->mBaseElement) + { + mData->mBaseElement->RecycleIconVisuals(); + mData->mHighlightIndex = -1; + } + } + +//--------------------------- Gesture ---------------------------------------- + +// --------------------------------------------------------------------------- +// SetHoldingEnabled +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SetHoldingEnabled() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SetHoldingEnabled"); + + mHelper->SetHoldingEnabled(EnhancedModeCondition()); + } + +// --------------------------------------------------------------------------- +// SetDoubleTapEnabled +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SetDoubleTapEnabled( bool aValue) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SetDoubleTapEnabled"); + + mHelper->SetDoubleTapEnabled( aValue ); + } + +// --------------------------------------------------------------------------- +// HandleGestureL +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleGestureL( const MGestureEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleGestureL"); + if(aEvent.IsHolding()) + { + HandleHoldGestureEvents(aEvent); + } + else + { + HandleNormalGestureEvents(aEvent); + } + } + +// --------------------------------------------------------------------------- +// HandleNormalGestureEvents +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleNormalGestureEvents( const MGestureEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleNormalGestureEvents"); + + switch ( aEvent.Code(MGestureEvent::EAxisHorizontal) ) + { + case EGestureStart: + { + SendFeedbackOnTouchDown(aEvent); + } + break; + case EGestureDrag: // fall through + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureDrag"); + if( aEvent.CurrentPos().iX > mData->mScreenWidth ) + { + return; + } + + if(TotalModelCount() > 0 ) + { + // if ui is on send event to applications + if( mData->mCoverFlow2DTemplate->IsUiOnOffFlagEnabled() && + (mData->mBaseElement->IsUiOnMode()) ) + { + CAlfWidgetControl::processEvent( TAlfEvent( ETypeSwitchUiStateOnDrag )); + } + + if (mData->mBounceInProgress && TotalModelCount() > 2) + { + mData->mBounceInProgress = false; + Env().CancelCustomCommands(this); + // bounce canceled once .dont bounce again for the next swipe. + mData->mDontBounce = true; + } + + int distance = aEvent.Distance().iX ; + mData->mCurrGestureDir = distance;//CovertDistAnceToDirection(distance); + if (mData->mIsMirrored) + { + distance = -distance; + } + mData->mReferencePoint = aEvent.CurrentPos().iX - 10; //pointerDownPos + distanceTravelled/2; + + mData->mBaseElement->StartDoodling(distance); + } + break; + } + + case EGestureTap: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureTap "); + HandleSingleTap(aEvent); + mFeedback->InstantFeedback(ETouchFeedbackList); + break; + } + + case EGestureDoubleTap: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureDoubleTap "); + if(TotalModelCount() <= 0 ) + { + //find out whether event should be sent on double tap or not + // in case of empty model and the feedback too. + break; + } + MulDoubleTapData doubleTapData; + // Finding the visual which has been hit . + CAlfVisual* hitVisual = aEvent.Visual(); + if(hitVisual && (hitVisual->Tag() == KCoverflowIndicator) ) + { + doubleTapData.mTapVisualIndex = mData->mHighlightIndex ; + } + else + { + int hitVisualIndex = GetHitVisualIndex( hitVisual ); + if( hitVisualIndex == -1 ) + { + break; + } + doubleTapData.mTapVisualIndex = hitVisualIndex; + } + doubleTapData.mDoubleTapPoint = aEvent.CurrentPos(); + + mFeedback->InstantFeedback(ETouchFeedbackList); + CAlfWidgetControl::processEvent ( TAlfEvent ( ETypeDoubleTap, + uint(&doubleTapData))); + break; + } + + case EGestureUnknown : + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureUnknown"); + if(TotalModelCount() > 0 ) + { + // this will revert to the original position if gesture get cancelled + // with some animation time. + // @TODO animation time should be same as set by application. + mData->mBaseElement->StopDoodling(200); + } + break; + } + + case EGestureSwipeLeft: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureSwipeLeft"); + if(TotalModelCount() > 0 ) + { + // do the calculations for changing teh higlight left or right depnding on last direction + // and the total direction moved. + int finalSwipeDirection = mData->mBaseElement->FinalSwipeDirection( + TotalSwipeDistance(aEvent),EEventScrollRight); + + HandleSwipe(finalSwipeDirection); + } + break; + } + + case EGestureSwipeRight: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureSwipeRight"); + if(TotalModelCount() > 0 ) + { + int finalSwipeDirection = mData->mBaseElement->FinalSwipeDirection( + TotalSwipeDistance(aEvent),EEventScrollLeft); + + HandleSwipe(finalSwipeDirection); + } + break; + } + case EGestureMultiTouchStart: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureMultiTouchStart"); + mData->mBaseElement->StopDoodling(0); + mFeedback->InstantFeedback(ETouchFeedbackMultiTouchRecognized); + break; + } + case EGestureMultiTouchReleased: + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureMultiTouchReleased"); + break; + case EGesturePinch: + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGesturePinch"); + CAlfWidgetControl::processEvent ( TAlfEvent ( ETypePinch,aEvent.PinchPercent())); + break; + case EGestureReleased: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleNormalGestureEvents EGestureReleased"); + break; + } + default: + break; + } // end of switch + } + +// --------------------------------------------------------------------------- +// TotalSwipeDistance +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::TotalSwipeDistance( const GestureHelper::MGestureEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::TotalSwipeDistance"); + if( aEvent.CurrentPos().iX > mData->mScreenWidth ) + { + return aEvent.Distance().iX - (aEvent.CurrentPos().iX - mData->mScreenWidth); + } + return aEvent.Distance().iX; + } + +// --------------------------------------------------------------------------- +// GetHitVisualIndex +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::GetHitVisualIndex( CAlfVisual* aHitVisual ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::GetHitVisualIndex"); + int visualIndex = -1; + + if(!aHitVisual) + { + // no visual found + return -1; + } + #ifdef _DEBUG + const TDesC8& buffer = aHitVisual->Tag(); + #endif + + if ((aHitVisual->Tag() != KCoverflowIcon)) + { + visualIndex = -1; + } + else + { + if(mData->mNumVisibleItem > 1) + { + CAlfLayout& iconFlow =mData->mBaseElement->FlowLayout( KIconFlowLayoutIndex ); + CAlfVisual* imgVisual = NULL; + for(int i=2; i<=4;i++) + { + imgVisual = iconFlow.Visual(i).FindTag(KCoverflowIcon); + if (imgVisual == aHitVisual) + { + visualIndex = RelativeToAbsolute(i); + break; + } + } + } + else + { + visualIndex = mData->mHighlightIndex; + } + } + return visualIndex; + } + + +// --------------------------------------------------------------------------- +// HandleSingleTap +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleSingleTap(const MGestureEvent& aEvent) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleSingleTap"); + + if(TotalModelCount() <= 0 ) + { + // in case of empty model and null model only when the empty text is set + // then only the selection event should be sent to the applications. + if( mData->mBaseElement->IsEmptyText() ) + { + SetSelection(-1); + } + // In case of null model and empty model if the empty text is not set then no need to calculate + //the hit visual index . Doest serve any purpose. + } + else + { + // Finding the visual which has been hit . + CAlfVisual* hitVisual = aEvent.Visual(); + if(hitVisual && (hitVisual->Tag() == KCoverflowIndicator) ) + { + CAlfWidgetControl::processEvent( TAlfEvent( EVideoIconSelect )); + return; + } + int hitVisualIndex = GetHitVisualIndex( hitVisual ); + if( hitVisualIndex > -1 ) + { + if( hitVisualIndex == mData->mHighlightIndex ) + { + SetSelection(mData->mHighlightIndex ); + } + else + { + //set the highlight in model + if(TotalModelCount() > 2 && hitVisualIndex == TotalModelCount()-1 + && mData->mHighlightIndex == 0) + { + HandleNavigationEvent ( EEventScrollLeft ); + } + else if(TotalModelCount() > 2 && mData->mHighlightIndex == TotalModelCount()-1 + && hitVisualIndex == 0) + { + HandleNavigationEvent ( EEventScrollRight ); + } + else if(hitVisualIndex > mData->mHighlightIndex) + { + HandleNavigationEvent ( EEventScrollRight ); + } + else + { + HandleNavigationEvent ( EEventScrollLeft ); + } + } + } + } + } + +// --------------------------------------------------------------------------- +// SendFeedbackOnTouchDown +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SendFeedbackOnTouchDown(const MGestureEvent& aEvent) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SendFeedbackOnTouchDown"); + + IMulModelAccessor* modelaccessor = ModelAccessor(); + if(!modelaccessor || modelaccessor->CurrentItemCount() == 0) + { + return; + } + CAlfVisual* hitVisual = aEvent.Visual(); + if((hitVisual && hitVisual->Tag() == KCoverflowIcon) || (mData->mCoverFlow2DTemplate->IsUiOnOffFlagEnabled() )) + { + mFeedback->InstantFeedback(ETouchFeedbackList); + } + } +// --------------------------------------------------------------------------- +// HandleSwipe +// Handle the swipe events (swipe left and swipe right) provided by the gesture helper. +// Also handles the extreme doodling case (it may happen that in doodling you can move two +// or three highlight before doing a pointer up) but gesture only gives us a swipe left and +// swipe right event. so we have to decide the no of highlight movement to do while getting +// left or right event. +// Also for 2 or 3 highlight movement if the 1st or 2nd highlight movement is the cycling case +// then we have to cancel the bounce as its already happend because of swipe. But the bounce +// will happen if the final highlight change is a cyclic case. +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleSwipe(int aEvent) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleSwipe"); + int event; + if(aEvent == EItemScrollLeft) + { + if (mData->mIsMirrored) + { + event = EEventScrollRight; + } + else + { + event = EEventScrollLeft; + } + } + else if(aEvent == EItemScrollRight) + { + if (mData->mIsMirrored) + { + event = EEventScrollLeft; + } + else + { + event = EEventScrollRight; + } + } + else + { + mData->mBaseElement->StopDoodling(200); + return; + } + + if(mData->mBaseElement->NumberOfSwipes() == EDoubleSwipe || mData->mBaseElement->NumberOfSwipes() == ETripleSwipe) + { + // done to avoid undesirable ui behaviour when we move the pointer little back. + // check if it can be done in another way. + CAlfEnv& env = Env(); + TAlfRefreshMode oldRefreshMode = env.RefreshMode(); + env.SetRefreshMode(EAlfRefreshModeManual); + if(mData->mBaseElement->NumberOfSwipes() == ETripleSwipe) + { + HandleNavigationEvent( event ); + } + HandleNavigationEvent( event ); + env.SetRefreshMode(oldRefreshMode); + } + + HandleNavigationEvent( event ); + // Feedback for swipe event + mFeedback->InstantFeedback(ETouchFeedbackList); + } + +// --------------------------------------------------------------------------- +// HandleHoldGestureEvents +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleHoldGestureEvents( const MGestureEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleHoldGestureEvents"); + + switch ( aEvent.Code(MGestureEvent::EAxisHorizontal) ) + { + case EGestureDrag: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleHoldGestureEvents EGestureDrag"); + + ReverseDirectionInFastScroll(aEvent); + + /// @todo The strip direction intially should start with the current gesture direction. + // But if u keep dragging without releasing the pointer tehn the directioon should chnage whenever + // the pointer crosses the centre of the screen. + + // if the pointer has crossed the centre position after holding started then the + // direction should depend on which half of teh screen + // else + // the direction should depend on the swipe direction + StartMoving(aEvent); + break; + } + + case EGestureReleased: + case EGestureTap: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleHoldGestureEvents EGestureReleased"); + HandleEnhancedStop(); + break; + } + + case EGestureHoldLeft: + case EGestureHoldRight: + { + MUL_LOG_INFO("MUL::MulCoverFlowControl:HandleHoldGestureEvents EGestureHoldLeft"); + if( EnhancedModeCondition() ) + { + EnhancedStarted( aEvent ); + } + break; + } + + default: + break; + } // end of switch + + } + +// --------------------------------------------------------------------------- +// ReverseDirectionInFastSrroll +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::ReverseDirectionInFastScroll(const MGestureEvent& aEvent) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::ReverseDirectionInFastScroll"); + + int distTravelled = aEvent.Distance().iX; + int pointerDownPos = aEvent.StartPos().iX; + int currPosition = aEvent.CurrentPos().iX; + int prevGestureDir = ConvertDistanceToDirection(mData->mCurrGestureDir); + + // if the distance travelled is negative i.e from right to left and the start position is on + // the right half of the screen and the direction has not changed yet , then special case to handle reference point. and vice versa + // case for left half of the screen. + if( ((distTravelled < 0 && pointerDownPos > mData->mScreenWidth/2 ) || (distTravelled > 0 && + pointerDownPos < mData->mScreenWidth/2 )) && mData->mReferencePoint != mData->mScreenWidth/2) + { + if( mData->mDirectionChanged ) + { + return; + } + + ChangeDirReferencePoint(currPosition,distTravelled); + } + else + { + // else the reference point will be the middle of the screen. + + // if the direction is not equal .. just check whether it has crossed the reference point. + // how to check whether it has crossed the reference point. + if(( prevGestureDir < 0 && currPosition > mData->mReferencePoint )||(prevGestureDir > 0 && currPosition < mData->mReferencePoint)) + { + mData->mCurrGestureDir *= -1; + } + + mData->mReferencePoint = mData->mScreenWidth/2; + } + } + +// --------------------------------------------------------------------------- +// ChangeDirReferencePoint +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::ChangeDirReferencePoint(int aCurrPosition, int aDistanceTravelled ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::ChangeDirReferencePoint"); + + int prevGestureDir = ConvertDistanceToDirection(mData->mCurrGestureDir); + int currGestureDir = ConvertDistanceToDirection(aDistanceTravelled); + + if( prevGestureDir != currGestureDir ) + { + // if the direction is not equal .. just check whether it has crossed the reference point. + // how to check whether it has crossed the reference point. + if(( prevGestureDir < 0 && aCurrPosition > mData->mReferencePoint )||(prevGestureDir > 0 && aCurrPosition < mData->mReferencePoint)) + { + //crossed the reference point first time .now no need to maintain the reference point .its always half of the screen + mData->mReferencePoint = mData->mScreenWidth/2; + mData->mDirectionChanged = true; + mData->mCurrGestureDir = aDistanceTravelled; + } + else + { + // not crossed the reference point yet + // still going in the same direction . + mData->mReferencePoint = aCurrPosition - 10; + } + } + else + { + // still going in the same direction . + if(( prevGestureDir < 0 && aCurrPosition < mData->mScreenWidth/2 )||(prevGestureDir > 0 + && aCurrPosition > mData->mScreenWidth/2)) + { + mData->mReferencePoint = mData->mScreenWidth/2; + } + else if(Abs(mData->mCurrGestureDir) < Abs(aDistanceTravelled) ) + { + // moving in the same direction in the increasing side towards the middle of the screen but hasnt + // crossed the reference point yet. + mData->mReferencePoint = aCurrPosition - 10; + } + } + } + +// --------------------------------------------------------------------------- +// ConvertDistanceToDirection +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::ConvertDistanceToDirection( int aDistance ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::ConvertDistanceToDirection"); + return aDistance>0?1:-1; + } + +// --------------------------------------------------------------------------- +// HandleEnhancedStop +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::HandleEnhancedStop() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleEnhancedStop"); + + CAlfWidgetControl::processEvent( TAlfEvent( ETypeFastScroll,EScrollStop )); + mCoverFlowAo->StopMoving(); + mData->mFastScroll = false; + mData->mGestureSpeed = 0; + // @TODO animation time should be same as set by the application. + mData->mBaseElement->MoveVisuals(0,200); + } + +// --------------------------------------------------------------------------- +// FastScrollTransitionTime +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::FastScrollTransitionTime() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::FastScrollTransitionTime"); + if (mData->mBounceInProgress) + { + return 800; + } + else + { + return mCoverFlowAo->FastScrollTransitionTime(); + } + } + + +// --------------------------------------------------------------------------- +// EnhancedModeCondition +// --------------------------------------------------------------------------- +// +bool MulCoverFlowControl::EnhancedModeCondition() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::EnhancedMode"); + if( !mData->mCoverFlow2DTemplate.get() ) + { + return false; + } + UString orientation = IsLandscape() ? UString(KLandscape) : UString(KPortrait); + + // If EMulWidgetFlagFastScroll is not set, + // or the current orientation is not landscape + // or in teh current template enhanced mode is not supported + if( !(((MulCoverFlowWidget*)widget())->IsFlagSet(IMulMultiItemWidget::EMulWidgetFlagFastScroll) + && !orientation.compare(KLandscape) + && mData->mCoverFlow2DTemplate->EnhancedTagParsed()) ) + { + return false; + } + // If template4(i.e. ui on off mode is anabled) then if ui on mode then ecf canot be launched,so return false + else if( mData->mCoverFlow2DTemplate->IsUiOnOffFlagEnabled() && + (mData->mBaseElement->IsUiOnMode()) ) + { + return false; + } + else + { + return true; // enhanced mode enabled + } + } + +// --------------------------------------------------------------------------- +// EnhancedStarted +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::EnhancedStarted(const GestureHelper::MGestureEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::EnhancedStarted"); + CAlfWidgetControl::processEvent( TAlfEvent( ETypeFastScroll,EScrollStart )); + mData->mFastScroll = true; + StartMoving(aEvent); + } + +// --------------------------------------------------------------------------- +// StartMoving +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::StartMoving( const GestureHelper::MGestureEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::StartMoving"); + + TRealPoint speedPoint = GestureSpeed( aEvent ); + int distance = mData->mCurrGestureDir; + if (mData->mIsMirrored) + { + distance = -distance; + } + mCoverFlowAo->StartMoving(speedPoint.iX, ConvertDistanceToDirection(distance) ); + mData->mGestureSpeed = speedPoint.iX; + } + +// --------------------------------------------------------------------------- +// GestureSpeed +// --------------------------------------------------------------------------- +// +TRealPoint MulCoverFlowControl::GestureSpeed( const MGestureEvent& aEvent ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::GestureSpeed"); + + TRect area(this->DisplayArea()); + TRect rect(TPoint(0,0),TPoint(area.Width(),area.Height())); + return aEvent.SpeedPercent( rect ); + } + +//--------------------Slider related functions---------------------------- + +// --------------------------------------------------------------------------- +// CreateSliderWidget +// --------------------------------------------------------------------------- +// +IAlfWidget* MulCoverFlowControl::CreateSliderWidget() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::CreateSliderWidget"); + + IAlfWidgetFactory& widgetFactory = AlfWidgetEnvExtension::widgetFactory(Env()); + IAlfWidget* sliderWidget = widgetFactory.findWidget( KNameSliderWidget ); + + if( sliderWidget ) + { + mSliderWidget = static_cast(sliderWidget); + mData->mBaseElement->UpdateSliderTick( 1 ); + } + else + { + // Get the template Id in Integer from your template data + //NOTE: Set template takes int as parameter not UString + + // Slider Widget creation + mSliderWidget = widgetFactory.createWidget ( KNameSliderWidget, KNameSliderWidget, *widget()->parent(), NULL); + IMulSliderModel* mSliderModel = widgetFactory.createModel ("mulslidermodel"); + mSliderWidget->setModel(mSliderModel, true); + mSliderModel->SetTemplate(ESliderTemplate1); + mSliderWidget->SetHandleKeyEvent(false); + mSliderWidget->control()->disableState(IAlfWidgetControl::Focusable); + } + + IAlfWidgetEventHandler* coverFlowEventHandler = static_cast ( + mData->mBaseElement->makeInterface( IAlfWidgetEventHandler::type() ) ); + + //Register the slidereventhandler and coverfloweventhandler with one another + mSliderWidget->control()->addEventHandler((coverFlowEventHandler)); + + return mSliderWidget; + } + +// --------------------------------------------------------------------------- +// GetSliderWidget +// --------------------------------------------------------------------------- +// +IAlfWidget* MulCoverFlowControl::GetSliderWidget() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::GetSliderWidget"); + + IAlfWidgetFactory& widgetFactory = AlfWidgetEnvExtension::widgetFactory(*(CAlfEnv::Static())); + return widgetFactory.findWidget( KNameSliderWidget ); + } + +// --------------------------------------------------------------------------- +// GetSliderModel +// --------------------------------------------------------------------------- +// +IMulSliderModel* MulCoverFlowControl::GetSliderModel() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::GetSliderModel"); + if( mSliderWidget ) + { + IMulSliderWidget* mulSliderWidget = static_cast(mSliderWidget); + IMulSliderModel* mulSliderModel = static_cast(mulSliderWidget->model()); + return mulSliderModel; + } + return NULL; + } + +// --------------------------------------------------------------------------- +// DestroySlider +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::DestroySlider() + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::DestroySlider"); + + MulBaseElement* baseelement = static_cast(findElement(KBase)); + if(baseelement) + { + baseelement->RemoveSliderFromLayout(); + } + + IAlfWidgetFactory& widgetFactory = AlfWidgetEnvExtension::widgetFactory(Env()); + IAlfWidget* sliderWidget = widgetFactory.findWidget( KNameSliderWidget ); + if( sliderWidget ) + { + IAlfElement* baseelement = findElement(KBase); + if(baseelement) + { + + IAlfWidgetEventHandler* coverFlowEventHandler = static_cast ( + baseelement->makeInterface( IAlfWidgetEventHandler::type() ) ); + + if( sliderWidget->control() ) + { + sliderWidget->control()->removeEventHandler(*(coverFlowEventHandler)); + } + + } + } + } + +// --------------------------------------------------------------------------- +// UpdateItemAtIndex +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::UpdateItemAtIndex(const int aRelativeIndex, int aAnimationTime) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::UpdateItemAtIndex"); + int absoluteIndex = RelativeToAbsolute(aRelativeIndex); + if(absoluteIndex >= 0) + { + UpdateCoverflowItem( absoluteIndex,aRelativeIndex, aAnimationTime ); + } + else + { + SetBlankTexture(aRelativeIndex); + } + } + +// --------------------------------------------------------------------------- +// SetBlankTexture +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SetBlankTexture(int aRelativeIndex) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SetBlankTexture"); + CAlfFlowLayout& iconFlow = static_cast(mData->mBaseElement->FlowLayout( KIconFlowLayoutIndex )); + + CAlfDeckLayout& layout = static_cast(iconFlow.Visual(aRelativeIndex)); + CAlfImageVisual* visual =static_cast(layout.FindTag(KCoverflowIcon)); + + CAlfTextureManager& textureMgr = Env().TextureManager(); + TAlfImage blankTexture = textureMgr.BlankTexture(); + visual->SetImage(blankTexture); + + // remove the icon brush if any. + mData->mBaseElement->RemoveBrushOnIcon(*visual); + + CAlfImageVisual* indicatorVisual =static_cast(layout.FindTag(KCoverflowIndicator)); + if(indicatorVisual) + { + indicatorVisual->SetImage(blankTexture); + } + } + +// --------------------------------------------------------------------------- +// UpdateCoverflowItem +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::UpdateCoverflowItem( int aItemIndex,int aVisualIndex, int aAnimationTime ) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::UpdateCoverflowItem"); + + CAlfFlowLayout& iconFlow = static_cast(mData->mBaseElement->FlowLayout( KIconFlowLayoutIndex )); + IMulModelAccessor* accessor = static_cast(widget()->model()); + + try + { + const MulVisualItem& item = accessor->Item(aItemIndex); + + CAlfDeckLayout& layout = static_cast(iconFlow.Visual(aVisualIndex)); + CAlfImageVisual* visual =static_cast(layout.FindTag(KCoverflowIcon)); + IMulVariantType* varData = item.Attribute(mulvisualitem::KMulIcon1); + if(varData && visual) + { + DoSetImage(varData,visual); + mData->mBaseElement->ApplyScaleMode(*visual); + } + else + { + if (mData->mDefaultTextureId >= 0) + { + const CAlfTexture* texture = Env().TextureManager().Texture (mData->mDefaultTextureId); + if(visual) + { + visual->SetImage (TAlfImage (*texture)); + } + mData->mBaseElement->ApplyScaleMode(*visual); + } + else + { + if(visual) + { + visual->SetImage(Env().TextureManager().BlankTexture()); + } + } + } + if(mData->mCoverFlow2DTemplate->IsUiOnOffFlagEnabled() ) + { + mData->mBaseElement->DisplayIndicatorIcon(item,aVisualIndex); + } + } + catch(...) + { + CAlfDeckLayout& layout = static_cast(iconFlow.Visual(aVisualIndex)); + CAlfImageVisual* visual =static_cast(layout.FindTag(KCoverflowIcon)); + if (mData->mDefaultTextureId >= 0) + { + const CAlfTexture* texture = Env().TextureManager().Texture (mData->mDefaultTextureId); + visual->SetImage (TAlfImage (*texture)); + mData->mBaseElement->ApplyScaleMode(*visual); + } + else + { + visual->SetImage(Env().TextureManager().BlankTexture()); + } + + }//catch ends + // if the item is the highlight item then update the text if required. + if (aVisualIndex == mData->mNumVisibleItem) + { + mData->mBaseElement->UpdateTextValue(aAnimationTime); + } + } + + +// --------------------------------------------------------------------------- +// DoSetImage +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::DoSetImage(IMulVariantType* aData,CAlfImageVisual* aImgVisual) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::DoSetImage"); + + if ( aData && aData->Type() == IMulVariantType::EDes) + { + TAlfImage image = AlfWidgetEnvExtension::resourcePool( + aImgVisual->Env()).getImageResource((char*)(aData->DesC().Ptr())); + if(image.HasTexture()) + { + aImgVisual->SetImage(image); + } + else if(IsSVGImage(aData->DesC())) + { + LoadImageFromSvg(aData->DesC(),*aImgVisual); + } + else + { + // check if the texture is already loaded + CAlfTextureManager& textureMgr = aImgVisual->Env().TextureManager(); + const TInt existingTextureId = textureMgr.TextureId( aData->DesC() ); + const CAlfTexture* texture = NULL; + + if ( existingTextureId != KErrNotFound ) + { + texture = textureMgr.Texture( existingTextureId ); + } + else + { + TRAPD( err, texture = &( textureMgr.LoadTextureL(aData->DesC(), + EAlfTextureFlagLoadAnimAsImage, KAlfAutoGeneratedTextureId ) ) ); + if( err != KErrNone ) + { + // means the texture is invalid. + //draw a blank texture here. + texture = &( textureMgr.BlankTexture() ); + } + } + aImgVisual->SetImage( TAlfImage( *texture ) ); + } + } + else if ( aData && aData->Type ()== IMulVariantType::EInt) + { + const CAlfTexture* texture = Env().TextureManager().Texture (aData->integer()); + aImgVisual->SetImage (TAlfImage (*texture)); + } + } + +// --------------------------------------------------------------------------- +// IsSVGImage +// --------------------------------------------------------------------------- +// +bool MulCoverFlowControl::IsSVGImage(const TDesC& aImagePath) + { + MUL_LOG_INFO("MUL:MulCoverFlowControl::IsSVGImage"); + _LIT(KSvgFile,".svg"); + + return (KErrNotFound != aImagePath.FindC(KSvgFile)); + } + +// --------------------------------------------------------------------------- +// LoadImageFromSvg +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::LoadImageFromSvg(const TDesC& aImagePath, + CAlfImageVisual& aImageVisual ) + { + MUL_LOG_INFO("MUL:MulCoverFlowControl::LoadImageFromSvg"); + + CAlfImageLoaderUtil imgLoaderUtil; + imgLoaderUtil.SetSize (TSize (50, 50)); + + MAlfBitmapProvider* iSvgBitMapProv= imgLoaderUtil.CreateSVGImageLoaderL (aImagePath); + CAlfTexture &texture = aImageVisual.Env().TextureManager().CreateTextureL ( + KAlfAutoGeneratedTextureId, + iSvgBitMapProv, + EAlfTextureFlagLoadAnimAsImage); + aImageVisual.SetImage (TAlfImage (texture)); + + } + +// --------------------------------------------------------------------------- +// StoreVisibleItemCount +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::StoreVisibleItemCount(int aVisibleItemCount) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::StoreVisibleItemCount"); + mData->mNumVisibleItem = aVisibleItemCount; + } + +// --------------------------------------------------------------------------- +// SetDefaultImage +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::SetDefaultImage(int aTextureId) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::SetDefaultImage"); + mData->mDefaultTextureId = aTextureId; + } + +// --------------------------------------------------------------------------- +// WindowTop +// --------------------------------------------------------------------------- +// +int MulCoverFlowControl::WindowTop(int aHighlightIndex) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::WindowTop"); + int visibleItems = 2 * mData->mNumVisibleItem + 1; + int windowTop = aHighlightIndex - (visibleItems / 2); + IMulModelAccessor* accessor = static_cast(widget()->model()); + if(accessor) + { + windowTop = (windowTop + visibleItems - 1) >= TotalModelCount() ? + TotalModelCount() - visibleItems : windowTop; + windowTop = windowTop > 0 ? windowTop : 0; + } + + return windowTop; + } + +// --------------------------------------------------------------------------- +// UpdateBaseElement +// --------------------------------------------------------------------------- +// +void MulCoverFlowControl::UpdateBaseElement(MulBaseElement* aBaseElement) + { + MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::UpdateBaseElement"); + mData->mBaseElement = aBaseElement; + } + +// --------------------------------------------------------------------------- +// IsLandscape +// --------------------------------------------------------------------------- +// +bool MulCoverFlowControl::IsLandscape() + { + bool ret; + TSize ScreenSz = AlfUtil::ScreenSize(); + if (ScreenSz.iWidth > ScreenSz.iHeight) + { + ret = true; + } + else + { + ret = false; + } + return ret; + } + +// --------------------------------------------------------------------------- +// Gesturehelper +// --------------------------------------------------------------------------- +// +GestureHelper::CGestureHelper* MulCoverFlowControl::Gesturehelper() + { + return mHelper.get(); + } + + } // namespace Alf + +//End of file