/*
* 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 <AknUtils.h>
// Alf Headers
#include <alf/alfenv.h>
// for dosetimage func
#include <alf/alfimageloaderutil.h>
#include <alf/alfbitmapprovider.h>
#include <alf/alfdisplay.h>
#include <alf/alfresourcepool.h> //for resource pooling
#include <alf/alfwidgetenvextension.h> //for resource pooling
#include <alf/alfutil.h>
#include <alf/alfimagevisual.h>
// Mul Headers
#include <mul/mulevent.h>
#include <mul/imulsliderwidget.h>
// Gesture Helper
#include <gesturehelper.h>
// 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<MulCoverFlowTemplate> 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<IMulModelAccessor*>(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<IMulModelAccessor*>(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<IMulModelAccessor*>(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<IMulModelAccessor*>(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<IMulModelAccessor*>(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<IMulModelAccessor*>(widget()->model());
if(accessor)
{
return accessor->CurrentItemCount();
}
return -1;
}
// ---------------------------------------------------------------------------
// HandleModelCountChange
// ---------------------------------------------------------------------------
//
void MulCoverFlowControl::HandleModelCountChange()
{
MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::HandleModelCountChange");
IMulModelAccessor* accessor = static_cast<IMulModelAccessor*>(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<IMulModelAccessor*>(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<IMulSliderWidget*>(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<IMulSliderWidget> ( KNameSliderWidget, KNameSliderWidget, *widget()->parent(), NULL);
IMulSliderModel* mSliderModel = widgetFactory.createModel<IMulSliderModel> ("mulslidermodel");
mSliderWidget->setModel(mSliderModel, true);
mSliderModel->SetTemplate(ESliderTemplate1);
mSliderWidget->SetHandleKeyEvent(false);
mSliderWidget->control()->disableState(IAlfWidgetControl::Focusable);
}
IAlfWidgetEventHandler* coverFlowEventHandler = static_cast<IAlfWidgetEventHandler*> (
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<IMulSliderWidget*>(mSliderWidget);
IMulSliderModel* mulSliderModel = static_cast<IMulSliderModel*>(mulSliderWidget->model());
return mulSliderModel;
}
return NULL;
}
// ---------------------------------------------------------------------------
// DestroySlider
// ---------------------------------------------------------------------------
//
void MulCoverFlowControl::DestroySlider()
{
MUL_LOG_ENTRY_EXIT("MUL:MulCoverFlowControl::DestroySlider");
MulBaseElement* baseelement = static_cast<MulBaseElement*>(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<IAlfWidgetEventHandler*> (
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<CAlfFlowLayout&>(mData->mBaseElement->FlowLayout( KIconFlowLayoutIndex ));
CAlfDeckLayout& layout = static_cast<CAlfDeckLayout&>(iconFlow.Visual(aRelativeIndex));
CAlfImageVisual* visual =static_cast<CAlfImageVisual*>(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<CAlfImageVisual*>(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<CAlfFlowLayout&>(mData->mBaseElement->FlowLayout( KIconFlowLayoutIndex ));
IMulModelAccessor* accessor = static_cast<IMulModelAccessor*>(widget()->model());
try
{
const MulVisualItem& item = accessor->Item(aItemIndex);
CAlfDeckLayout& layout = static_cast<CAlfDeckLayout&>(iconFlow.Visual(aVisualIndex));
CAlfImageVisual* visual =static_cast<CAlfImageVisual*>(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<CAlfDeckLayout&>(iconFlow.Visual(aVisualIndex));
CAlfImageVisual* visual =static_cast<CAlfImageVisual*>(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<IMulModelAccessor*>(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