diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/src/akngridview.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/AvKon/src/akngridview.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,2040 @@ +/* +* Copyright (c) 2002-2009 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: CAknGridView handles the drawing, the mapping +* of the grid data index to the underlying listbox index (and +* vice versa) as well as the movement around the grid. +* +*/ + +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST +#include +#include +#endif //RD_UI_TRANSITION_EFFECTS_LIST +#include "akntrace.h" + +/** + * Local Panic Function and Panic Codes + */ +enum TAknGridViewPanicCodes + { + EAknPanicGridViewGeneralPanic, + EAknPanicGridViewInvalidRowIndex, + EAknPanicGridViewInvalidColumnIndex, + EAknPanicGridViewNoGraphicsContext, + EAknPanicGridViewNoModel, + EAknPanicGridViewInvalidNumberOfRows, + EAknPanicGridViewInvalidNumberOfColumns, + EAknPanicGridViewInvalidItemWidth, + EAknPanicGridViewInvalidItemHeight + }; + +GLDEF_C void Panic(TAknGridViewPanicCodes aPanic) + { + _LIT(KPanicCat,"AknGridView"); + User::Panic(KPanicCat, aPanic); + } + + +/** + * Constructor + */ +EXPORT_C CAknGridView::CAknGridView() + { + iScrollingType = EScrollFollowsItemsAndLoops; + iScrollInSecondaryDimension = EScrollFollowsItemsAndLoops; + iGridDetails.iGridDimensions = TSize(1,1); + } + +/** + * Destructor + */ +EXPORT_C CAknGridView::~CAknGridView() + { + } + +// data index <-> row/column calculation + +/** + * Converts a logical position on the grid, where the coordinates are with respect to + * the top left hand corner of the grid, to an index for the cell with respect to the + * ordering of the cells in the grid. + */ +EXPORT_C void CAknGridView::DataIndexFromLogicalPos( + TInt& aItemIndex, + TInt aRowIndex, + TInt aColIndex) const + { + _AKNTRACE_FUNC_ENTER; + // row and column orientated from top left corner which is (0,0) + + // check minimums + __ASSERT_ALWAYS((aRowIndex >= 0), Panic(EAknPanicGridViewInvalidRowIndex)); + __ASSERT_ALWAYS((aColIndex >= 0), Panic(EAknPanicGridViewInvalidColumnIndex)); + + _AKNTRACE( "[%s] aItemIndex = %d aRowIndex = %d aColIndex = %d", + __FUNCTION__, aItemIndex, aRowIndex, aColIndex ); + // calculate number of cells from lowest index corner + if (IsPrimaryVertical()) + { + // work out how many complete columns from lowest index + // to required position + TInt numOfCols = aColIndex; + if (!(iGridDetails.iGridFlags & ELeftToRight)) + numOfCols = (iGridDetails.iGridDimensions.iWidth - 1) - numOfCols; + + // process the row to calculate final index value depending + // on orientation of lowest index with respect to the top to + // bottom numbering of the rows. + TInt adjustment = aRowIndex; + if (!(iGridDetails.iGridFlags & ETopToBottom)) + { + adjustment = -(adjustment + 1); + numOfCols++; + } + + aItemIndex = numOfCols * NumberOfRowsInView(); + aItemIndex += adjustment; + } + else + { + TInt numOfRows = aRowIndex; + if (!(iGridDetails.iGridFlags & ETopToBottom)) + numOfRows = (iGridDetails.iGridDimensions.iHeight - 1) - numOfRows; + + TInt numOfCols = aColIndex; + if (!(iGridDetails.iGridFlags & ELeftToRight)) + { + numOfCols = (NumberOfColsInView() - 1) - numOfCols; + } + + aItemIndex = numOfRows * NumberOfColsInView(); + aItemIndex += numOfCols; + } + _AKNTRACE_FUNC_EXIT; + } + +/** + * Converts an index for a cell in the grid, given with respect to the ordering + * of the cells in the grid, to a logical position on the grid, where the coordinates + * are with respect to the top left hand corner of the grid. + */ +EXPORT_C void CAknGridView::LogicalPosFromDataIndex( + TInt aItemIndex, + TInt& aRowIndex, + TInt& aColIndex) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d aRowIndex = %d aColIndex = %d", + __FUNCTION__, aItemIndex, aRowIndex, aColIndex ); + // refer to DataIndexFromLogicalPos above for explanation of mapping of data indexes + if (aItemIndex > 0) + { + if (IsPrimaryVertical()) + { + aColIndex = aItemIndex / NumberOfRowsInView(); + aRowIndex = aItemIndex % NumberOfRowsInView(); + } + else + { + aRowIndex = aItemIndex / NumberOfColsInView(); + aColIndex = aItemIndex % NumberOfColsInView(); + } + } + else + { + aRowIndex = 0; + aColIndex = 0; + } + + if (!(iGridDetails.iGridFlags & ELeftToRight)) + aColIndex = (iGridDetails.iGridDimensions.iWidth - 1) - aColIndex; + + if (!(iGridDetails.iGridFlags & ETopToBottom)) + aRowIndex = (iGridDetails.iGridDimensions.iHeight - 1) - aRowIndex; + + if (aColIndex < 0) + aColIndex = 0; + if (aRowIndex < 0) + aRowIndex = 0; + _AKNTRACE_FUNC_EXIT; + } + +/** + * Converts a CEikListBox index for a cell in the grid, given with respect to the + * snaking listbox top down, left to right structure underlying the grid + * structure, to a logical position on the grid, where the coordinates are with + * respect to the top left hand corner of the grid. + */ +EXPORT_C void CAknGridView::ListBoxIndexFromLogicalPos( + TInt& aItemIndex, + TInt aRowIndex, + TInt aColIndex) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d aRowIndex = %d aColIndex = %d", + __FUNCTION__, aItemIndex, aRowIndex, aColIndex ); + // check minimums + __ASSERT_DEBUG((aRowIndex >= 0), Panic(EAknPanicGridViewInvalidRowIndex)); + __ASSERT_DEBUG((aColIndex >= 0), Panic(EAknPanicGridViewInvalidColumnIndex)); + + if(IsPrimaryVertical()) + { + aItemIndex = aColIndex * NumberOfRowsInView(); + aItemIndex += aRowIndex; + } + else + { + aItemIndex = aRowIndex * NumberOfColsInView(); + aItemIndex += aColIndex; + } + _AKNTRACE_FUNC_EXIT; + } + +/** + * Converts a logical position on the grid, where the coordinates are with respect to + * the top left hand corner of the grid, to a CEikListBox index for the cell with + * respect to the snaking listbox top down, left to right structure underlying the + * grid structure. + */ +EXPORT_C void CAknGridView::LogicalPosFromListBoxIndex(TInt aItemIndex, TInt& aRowIndex, TInt& aColIndex) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d aRowIndex = %d aColIndex = %d", + __FUNCTION__, aItemIndex, aRowIndex, aColIndex ); + aColIndex = 0; + aRowIndex = 0; + + if (aItemIndex) + { + if(IsPrimaryVertical()) + { + aColIndex = aItemIndex / NumberOfRowsInView(); + aRowIndex = aItemIndex % NumberOfRowsInView(); + } + else + { + aColIndex = aItemIndex % NumberOfColsInView(); + aRowIndex = aItemIndex / NumberOfColsInView(); + } + } + _AKNTRACE_FUNC_EXIT; + } + +// data index <-> listbox index conversion routines + +/** + * Converts an underlying CEikListBox index into the equivalent grid + * cell index given with respect to the ordering of the cells in the grid. + */ +EXPORT_C TInt CAknGridView::ActualDataIndex(TInt aListBoxIndex) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aListBoxIndex = %d", + __FUNCTION__, aListBoxIndex ); + TInt logicalRow = 0; + TInt logicalCol = 0; + LogicalPosFromListBoxIndex(aListBoxIndex, logicalRow, logicalCol); + + TInt dataIndex = 0; + DataIndexFromLogicalPos(dataIndex, logicalRow, logicalCol); + + _AKNTRACE_FUNC_EXIT; + return dataIndex; + } + +/** + * Converts a grid cell index into the equivalent CEikListBox index for + * the underlying snaking listbox top down, left to right structure. + */ +EXPORT_C TInt CAknGridView::ListBoxIndex(TInt aDataIndex) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aDataIndex = %d", + __FUNCTION__, aDataIndex ); + TInt logicalRow = 0; + TInt logicalCol = 0; + LogicalPosFromDataIndex(aDataIndex, logicalRow, logicalCol); + + TInt listBoxIndex = 0; + ListBoxIndexFromLogicalPos(listBoxIndex, logicalRow, logicalCol); + + _AKNTRACE_FUNC_EXIT; + return listBoxIndex; + } + +// the current data item +/** + * Returns the current data index with respect to the ordering of the cells in + * the grid. + */ +EXPORT_C TInt CAknGridView::CurrentDataIndex() const + { + return ActualDataIndex(iCurrentItemIndex); + } + +/** + * Sets the current data index with a value given with respect to the ordering of + * the cells in the grid. + */ +EXPORT_C void CAknGridView::SetCurrentDataIndex(TInt aDataIndex) + { + _AKNTRACE( "[%s] aDataIndex = %d", + __FUNCTION__, aDataIndex ); + TRAP_IGNORE(MoveToItemIndexL(ListBoxIndex(aDataIndex),ENoSelection)); + } + +// grid functions + +/** + * Checks that number of cells in the grid is always enough to fill the + * current grid dimensions. This method should be called after any + * method that may alter the amount of data within the grid. + * + */ +EXPORT_C void CAknGridView::SetGridCellDimensions(TSize aGridDimensions) + { + // set the new grid size + iGridDetails.iGridDimensions = aGridDimensions; + } + +/** + * Returns the current grid dimensions. + */ +EXPORT_C TSize CAknGridView::GridCellDimensions() const + { + return iGridDetails.iGridDimensions; + } + +/** + * Sets the size of the spaces between items. + */ +EXPORT_C void CAknGridView::SetSpacesBetweenItems(TSize aSizeOfSpaceBetweenItems) + { + iGridDetails.iSizeBetweenItems = TSize(0,0); + if (aSizeOfSpaceBetweenItems.iWidth > 0) + { + iGridDetails.iSizeBetweenItems.iWidth=aSizeOfSpaceBetweenItems.iWidth; + } + if (aSizeOfSpaceBetweenItems.iHeight > 0) + { + iGridDetails.iSizeBetweenItems.iHeight=aSizeOfSpaceBetweenItems.iHeight; + } + } + +/** + * Sets the form of scroll to activate upon reaching the limit when moving in + * the primary direction of grid, primary meaning whether the items are + * organised vertically or horizontally. + */ +EXPORT_C void CAknGridView::SetPrimaryScrollingType(TScrollingType aScrollingType) + { + iScrollingType = aScrollingType; + } + +/** + * Sets the form of scroll to activate upon reaching the limit when moving in + * the secondary direction of grid. + */ +EXPORT_C void CAknGridView::SetSecondaryScrollingType(TScrollingType aSecondaryScrolling) + { + iScrollInSecondaryDimension = aSecondaryScrolling; + } + + +/** + * Returns true if the primary dimension of the grid is + * vertical. + */ +EXPORT_C TBool CAknGridView::IsPrimaryVertical() const + { + return (iGridDetails.iGridFlags & EPrimaryIsVertical); + } + +/** + * Returns ETrue if the CEikListBox index given exists. + */ +EXPORT_C TBool CAknGridView::ItemExists(TInt aListBoxIndex) const + { + TInt totalpossibleitems = iGridDetails.iGridDimensions.iHeight * iGridDetails.iGridDimensions.iWidth; + + return ((aListBoxIndex > -1) && (aListBoxIndex < totalpossibleitems)); + } + + +/** + * This has been overloaded to ensure that only valid cells are drawn + * and not the empty cells. + */ +EXPORT_C void CAknGridView::DrawItem( TInt aItemIndex ) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d", + __FUNCTION__, aItemIndex ); + if ( RedrawDisabled() || !IsVisible() ) + { + _AKNTRACE_FUNC_EXIT; + return; + } + + if ( ItemExists( aItemIndex ) ) + { + TBool transparencyEnabled( CAknEnv::Static()->TransparencyEnabled() ); + TBool drawingInitiated = ETrue; + TPoint itemPosition( ItemPos( aItemIndex ) ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = + CAknListLoader::TfxApiInternal( iGc ); +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + if ( transparencyEnabled ) + { + if ( iWin && iWin->GetDrawRect() == TRect::EUninitialized ) + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + drawingInitiated = transApi && !transApi->EffectsDisabled(); +#else + drawingInitiated = EFalse; +#endif + } + + if ( !drawingInitiated ) + { + TRect itemRect( itemPosition, ItemSize( aItemIndex ) ); + itemRect.Intersection( iViewRect ); + iWin->Invalidate( itemRect ); + iWin->BeginRedraw( itemRect ); + } + } + + // convert to actual data index + TInt dataIndex = ActualDataIndex( aItemIndex ); + + __ASSERT_DEBUG( (iGc), Panic( EAknPanicGridViewNoGraphicsContext ) ); + + if ( GridModel()->IndexContainsData( dataIndex ) ) + { + // It must be ensured here that an item isn't drawn outside + // the view rectangle. +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListNotSpecified ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + iGc->SetClippingRect( iViewRect ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + iItemDrawer->DrawItem( + dataIndex, + itemPosition, + ItemIsSelected( aItemIndex ), + aItemIndex == iCurrentItemIndex, + ( iFlags & EEmphasized ) == EEmphasized, + ( iFlags & EDimmed ) == EDimmed ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListNotSpecified ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + iGc->CancelClippingRect(); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + } + else + { + static_cast( iItemDrawer )-> + DrawEmptyItem( dataIndex, + ItemPos( aItemIndex ), + ( iFlags & EDimmed ) == EDimmed ); + } + + if ( transparencyEnabled && !drawingInitiated ) + { + iWin->EndRedraw(); + } + } + _AKNTRACE_FUNC_EXIT; + } + + +/** + * This has been overloaded to ensure that if no cells exist in the + * grid then an empty grid is displayed. And also to correct drawing. + */ +EXPORT_C void CAknGridView::Draw( const TRect* aClipRect ) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "The rect of grid are ( %d, %d ) ( %d, %d )", + aClipRect->iTl.iX, aClipRect->iTl.iY, + aClipRect->iBr.iX, aClipRect->iBr.iY ); + if ( RedrawDisabled() || iItemHeight == 0 || ColumnWidth() == 0 ) + { + _AKNTRACE_FUNC_EXIT; + return; + } + + if ( GridModel()->NumberOfData() == 0 ) + { + DrawEmptyList(); + } + else + { + if (RedrawDisabled()) + { + _AKNTRACE_FUNC_EXIT; + return; + } + __ASSERT_DEBUG(iModel, Panic(EAknPanicGridViewNoModel)); + if (iItemHeight == 0) + { + _AKNTRACE_FUNC_EXIT; + return; + } + if ( !aClipRect ) + { + aClipRect = &iViewRect; + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iGc ); + if ( transApi ) + { + aClipRect = &iViewRect; + transApi->SetListType( MAknListBoxTfxInternal::EListBoxTypeGrid ); + transApi->StartDrawing( MAknListBoxTfxInternal::EListNotSpecified ); + } +#endif //RD_UI_TRANSITION_EFFECTS_LIST + + iGc->SetClippingRect( *aClipRect ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif + + TInt numberOfItems( iModel->NumberOfItems() ); + TInt numberOfCols( NumberOfColsInView() ); + TInt numberOfCells( numberOfItems ); + TInt emptyCellsAtEnd( numberOfItems % numberOfCols ); + if ( emptyCellsAtEnd ) + { + // Add empty cells to the last row if it's not full so + // that the whole row gets it's background drawn. + numberOfCells += ( numberOfCols - emptyCellsAtEnd ); + } + TInt numberOfRows( numberOfCells / numberOfCols ); + TInt firstPotentialItemIndex = iTopItemIndex >= numberOfCols ? iTopItemIndex - numberOfCols : iTopItemIndex; + TInt lastPotentialItemIndex = iTopItemIndex + + ( NumberOfItemsThatFitInRect(iViewRect) * numberOfCols - 1 ) + numberOfCols; + + if ( lastPotentialItemIndex / numberOfCols > numberOfRows ) + { + // Check that there isn't an empty row at the bottom. + lastPotentialItemIndex -= numberOfCols; + } + + // Clear the unused portion of the viewing area. + DrawUnusedViewPortion(); + + for ( TInt i = firstPotentialItemIndex; i <= lastPotentialItemIndex; i++ ) + { + if ( ItemExists( i ) ) + { + DrawItem( i ); + } + else + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListView ); + } +#endif + + iGc->SetClippingRect( *aClipRect ); + ClearUnusedItemSpace( i, lastPotentialItemIndex ); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif + break; + } + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListView ); + } +#endif + + + iGc->CancelClippingRect(); + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif //RD_UI_TRANSITION_EFFECTS_LIST + } + _AKNTRACE_FUNC_EXIT; + } + + +// --------------------------------------------------------------------------- +// This function has been overloaded to draw items correctly. +// --------------------------------------------------------------------------- +// +EXPORT_C TPoint CAknGridView::ItemPos( TInt aItemIndex ) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d", + __FUNCTION__, aItemIndex ); + TInt rowIndex = 0; + TInt colIndex = 0; + CalcRowAndColIndexesFromItemIndex( aItemIndex, rowIndex, colIndex ); + + TPoint itemPos( + iViewRect.iTl.iX + colIndex * + ( ColumnWidth() + iGridDetails.iSizeBetweenItems.iWidth ), + iViewRect.iTl.iY + rowIndex * + ( iItemHeight + iGridDetails.iSizeBetweenItems.iHeight ) + iVerticalOffset ); + + _AKNTRACE_FUNC_EXIT; + return itemPos; + } + + +// --------------------------------------------------------------------------- +// This function has been overloaded to draw items correctly. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknGridView::CalcBottomItemIndex() + { + _AKNTRACE_FUNC_ENTER; + TInt numberOfItems( iModel->NumberOfItems() ); + iBottomItemIndex = + iTopItemIndex + iGridDetails.iPageSize - 1 + iGridDetails.iColsInView; + if ( iBottomItemIndex - iGridDetails.iColsInView >= numberOfItems - 1 ) + { + iBottomItemIndex -= iGridDetails.iColsInView; + } + _AKNTRACE_FUNC_EXIT; + } + + +// --------------------------------------------------------------------------- +// This function has been overloaded to draw items correctly. +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAknGridView::CalcNewTopItemIndexSoItemIsVisible( + TInt aItemIndex ) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d", + __FUNCTION__, aItemIndex ); + TInt newTopItemIndex = iTopItemIndex; + + if ( aItemIndex != iTopItemIndex ) + { + if ( IsPrimaryVertical() ) + { + TInt numOfRowsInView = NumberOfRowsInView(); + TInt colIndexOfTargetItem = aItemIndex / numOfRowsInView; + TInt numOfColsInView = NumberOfColsInView(); + if ( aItemIndex < iTopItemIndex ) + { + newTopItemIndex = colIndexOfTargetItem * numOfRowsInView; + } + else if ( aItemIndex > iBottomItemIndex ) + { + TInt colIndexOfNewBottomItem = colIndexOfTargetItem; + TInt colIndexOfNewTopItem = + colIndexOfNewBottomItem - ( numOfColsInView - 1 ); + newTopItemIndex = colIndexOfNewTopItem * numOfRowsInView; + } + } + else + { + TInt numOfColsInView = NumberOfColsInView(); + TInt rowIndexOfTargetItem = aItemIndex / numOfColsInView; + TInt numOfRowsInView = NumberOfRowsInView(); + + if ( aItemIndex < iTopItemIndex ) + { + newTopItemIndex = rowIndexOfTargetItem * numOfColsInView; + } + else if ( aItemIndex > iBottomItemIndex - numOfColsInView ) + { + TInt rowIndexOfNewBottomItem = rowIndexOfTargetItem; + TInt rowIndexOfNewTopItem = + rowIndexOfNewBottomItem - ( numOfRowsInView - 1 ); + newTopItemIndex = rowIndexOfNewTopItem * numOfColsInView; + } + } + } + + _AKNTRACE_FUNC_EXIT; + return newTopItemIndex; + } + + +/** + * This function has been overloaded to draw items correctly. + */ +EXPORT_C void CAknGridView::DrawItemRange( TInt aStartItemIndex, + TInt aEndItemIndex ) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aStartItemIndex = %d aEndItemIndex = %d", + __FUNCTION__, aStartItemIndex, aEndItemIndex ); + if ( RedrawDisabled() || iItemHeight == 0 ) + { + _AKNTRACE_FUNC_EXIT; + return; + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iGc ); +#endif + // Clear the unused portion of the viewing area. + DrawUnusedViewPortion(); + + for ( TInt i = aStartItemIndex; i <= aEndItemIndex; i++ ) + { + if ( ItemExists( i ) ) + { + DrawItem( i ); + } + else + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListView ); + } +#endif + ClearUnusedItemSpace( i, aEndItemIndex ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif + break; + } + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StartDrawing( MAknListBoxTfxInternal::EListView ); + } +#endif + + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->StopDrawing(); + } +#endif + _AKNTRACE_FUNC_EXIT; + } + +/** + * This function may be overloaded to detail an empty grid as required. + */ +EXPORT_C void CAknGridView::DrawEmptyList() const + { + _AKNTRACE_FUNC_ENTER; + iGc->SetClippingRect(iViewRect); + iItemDrawer->ClearRect(iViewRect); + + if (EmptyListText()) + { + // display empty grid message + CFormattedCellListBoxItemDrawer *id = (CFormattedCellListBoxItemDrawer*)ItemDrawer(); + AknDrawWithSkins::DrawEmptyList(iViewRect, *iGc, *EmptyListText(), id->FormattedCellData()->Control()); + } + iGc->CancelClippingRect(); + _AKNTRACE_FUNC_EXIT; + } + +/** + * Grid initialisation function. Should only be called by SetLayoutL of + * grid box. + */ +EXPORT_C void CAknGridView::SetGridDetails(SGrid aGridDetails) + { + SGrid details = aGridDetails; + + if (details.iSizeBetweenItems.iHeight < 0) + { + details.iSizeBetweenItems.iHeight = 0; + } + if (details.iSizeBetweenItems.iWidth < 0) + { + details.iSizeBetweenItems.iWidth = 0; + } + + iGridDetails = details; + } + + +// --------------------------------------------------------------------------- +// This set the current item index and moves the highlight to the specified +// item index and and scrolls the grid if necessary. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknGridView::MoveToItemIndexL( TInt aItemIndex, + TSelectionMode aSelectionMode ) + { + _AKNTRACE_FUNC_ENTER; + if ( !ItemExists( aItemIndex ) ) + { + _AKNTRACE_FUNC_EXIT; + return; // nothing to do + } + _AKNTRACE( "[%s] aItemIndex = %d TSelectionMode = %d", + __FUNCTION__, aItemIndex, aSelectionMode ); +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iGc ); + if ( transApi ) + { + transApi->SetMoveType( MAknListBoxTfxInternal::EListStartUnknownMove ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + TInt oldItemIndex = iCurrentItemIndex; + + if ( !ScrollToMakeItemVisible( aItemIndex ) ) + { + if ( ItemIsPartiallyVisible( aItemIndex ) ) + { + // ScrollToMakeItemVisible doesn't scroll the view for + // partial items, so for key events the scrolling is done here. + + TInt amountToScroll = + CalculateHScrollOffsetSoItemIsVisible( aItemIndex ); + + iHScrollOffset += amountToScroll; + iCurrentItemIndex = aItemIndex; + + if ( iExtension && !iExtension->iScrollingDisabled ) + { + CFormattedCellListBoxItemDrawer* itemDrawer = + static_cast( iItemDrawer ); + CEikListBox* listBox = + static_cast( + itemDrawer->FormattedCellData()->Control() ); + listBox->HandlePhysicsScrollEventL( + amountToScroll * iItemHeight + ItemOffsetInPixels() ); + } + else + { + // Do normal scrolling if physics are not enabled. + VScrollTo( CalcNewTopItemIndexSoItemIsVisible( aItemIndex ) ); + } + } + else + { + // View was not scrolled, so item is already visible. + iCurrentItemIndex = aItemIndex; + DrawItem( oldItemIndex ); + } + } + + UpdateSelectionL( aSelectionMode ); // this draws iCurrentItemIndex + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( transApi ) + { + transApi->SetMoveType( MAknListBoxTfxInternal::EListStopUnknownMove ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + _AKNTRACE_FUNC_EXIT; + } + + +// --------------------------------------------------------------------------- +// Returns the number of visible columns. +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAknGridView::NumberOfColsInView() const + { + __ASSERT_ALWAYS( ( iGridDetails.iColsInView > 0 ), + Panic( EAknPanicGridViewInvalidNumberOfColumns ) ); + return iGridDetails.iColsInView; + } + + +// --------------------------------------------------------------------------- +// Returns the number of visible rows. +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAknGridView::NumberOfRowsInView() const + { + __ASSERT_ALWAYS( ( iGridDetails.iRowsInView > 0 ), + Panic( EAknPanicGridViewInvalidNumberOfRows ) ); + TInt rows = iGridDetails.iRowsInView; + + return rows; + } + + +void CAknGridView::MoveCursorWithRepeatsL( + TBool aNextOrPrev, TSelectionMode aSelectionMode, TInt aAmount ) + { + _AKNTRACE_FUNC_ENTER; + TBool singleColumn = EFalse; + if ( IsPrimaryVertical() ) + { + singleColumn = iGridDetails.iGridDimensions.iHeight < 2; + } + else + { + singleColumn = iGridDetails.iGridDimensions.iWidth < 2; + } + + TCursorMovement cursorMovement; + if ( aNextOrPrev ) + { + cursorMovement = CListBoxView::ECursorNextColumn; + if ( singleColumn ) + { + cursorMovement = CListBoxView::ECursorNextItem; + } + } + else + { + cursorMovement = CListBoxView::ECursorPreviousColumn; + if ( singleColumn ) + { + cursorMovement = CListBoxView::ECursorPreviousItem; + } + } + + TInt step = aAmount; + if ( !singleColumn ) + { + // Stop looping in grids. Looping is still allowed in list like grid. + TInt maxIndex = GridModel()->NumberOfData() - 1; + TInt dataIndex = CurrentDataIndex(); + TBool isToTail = iGridDetails.iGridFlags & ELeftToRight ? + aNextOrPrev : !aNextOrPrev; + + if ( dataIndex + step > maxIndex && isToTail ) + { + step = maxIndex - dataIndex; + } + + if ( dataIndex < step && !isToTail ) + { + step = dataIndex; + } + } + + for ( TInt ii = 0; ii < step; ii++ ) + { + MoveCursorL( cursorMovement, aSelectionMode ); + } + _AKNTRACE_FUNC_EXIT; + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST +// ----------------------------------------------------------------------------- +// LISTBOX EFFECTS IMPLEMENTATION +// +// Sets movement type in the transition controller +// +// This function is called from DoMoveL before MoveToItemIndexL is called. +// ----------------------------------------------------------------------------- +// +void SetMoveType( CWindowGc* aGc, + CAknGridView::TCursorMovement aCursorMovement ) + { + MAknListBoxTfxInternal* api = CAknListLoader::TfxApiInternal( aGc ); + if ( api ) + { + if ( aCursorMovement == CAknGridView::ECursorNextColumn) + { + api->SetMoveType( MAknListBoxTfxInternal::EListMoveRight ); + } + else if ( aCursorMovement == CAknGridView::ECursorNextItem ) + { + api->SetMoveType( MAknListBoxTfxInternal::EListMoveDown ); + } + else if ( aCursorMovement == CAknGridView::ECursorPreviousItem ) + { + api->SetMoveType( MAknListBoxTfxInternal::EListMoveUp ); + } + else if ( aCursorMovement == CAknGridView::ECursorPreviousColumn ) + { + api->SetMoveType( MAknListBoxTfxInternal::EListMoveLeft ); + } + else + { + api->SetMoveType( MAknListBoxTfxInternal::EListNoMovement ); + } + } + } +#endif //RD_UI_TRANSITION_EFFECTS_LIST + +EXPORT_C void CAknGridView::DoMoveL(TCursorMovement aCursorMovement, TSelectionMode aSelectionMode) + { + _AKNTRACE_FUNC_ENTER; + TInt rowIndex = 0; + TInt colIndex = 0; + LogicalPosFromListBoxIndex(iCurrentItemIndex, rowIndex, colIndex); + + TBool moveDown = IsMoveDown(aCursorMovement); + TBool moveRight = IsMoveRight(aCursorMovement); + + TInt newIndex = 0; + TScrollingType scrollingType = EScrollStops; + TBool moveIsVert = (aCursorMovement==ECursorNextItem)||(aCursorMovement==ECursorPreviousItem); + TBool moveInPrim = COMPARE_BOOLS(IsPrimaryVertical(),(moveIsVert)); + if (moveInPrim) + scrollingType = iScrollingType; + else + scrollingType = iScrollInSecondaryDimension; + + switch(scrollingType) + { + case EScrollStops: // drop through + case EScrollFollowsGrid: // drop through + case EScrollFollowsItemsAndStops: // drop through + case EScrollFollowsItemsAndLoops: + newIndex = SearchByLines(colIndex, rowIndex, aCursorMovement); + break; + case EScrollIncrementLineAndStops: // drop through + case EScrollIncrementLineAndLoops: + { + TBool edgePassed = IsEdgePassed(iCurrentItemIndex, moveDown, moveRight, !moveIsVert, EFalse, newIndex); + if (!moveInPrim && edgePassed && (newIndex >=0)) + {// special scroll + TBool specialMoveNeeded = EFalse; + LogicalPosFromListBoxIndex(newIndex, rowIndex, colIndex); + if (moveIsVert) + if ((rowIndex != 0) && (rowIndex != iGridDetails.iGridDimensions.iHeight - 1)) + specialMoveNeeded = ETrue; + else + if ((colIndex != 0) && (colIndex != iGridDetails.iGridDimensions.iWidth - 1)) + specialMoveNeeded = ETrue; + if (specialMoveNeeded) + {// fake being at the far edge of the grid + if (moveRight) + colIndex = 0; + else + colIndex = iGridDetails.iGridDimensions.iWidth - 1; + + if (moveDown) + rowIndex = 0; + else + rowIndex = iGridDetails.iGridDimensions.iHeight - 1; + + TInt newIndex2 = 0; // fake index + ListBoxIndexFromLogicalPos(newIndex2, rowIndex, colIndex); + iTopItemIndex = CalcNewTopItemIndexSoItemIsVisible(newIndex2); + CalcBottomItemIndex(); + iCurrentItemIndex = newIndex; // set current to actual index we want to move to + iHScrollOffset += CalculateHScrollOffsetSoItemIsVisible(newIndex); + DrawItemRange(iTopItemIndex, iBottomItemIndex); // draw range for fake index + if (ItemIsVisible(newIndex)) + return; // moved and drawn + // need to scroll some more to make the newIndex visable + } + } + } + break; + default: + break; + } + + if (newIndex >=0) + { // found next item to move to +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + SetMoveType( iGc, aCursorMovement ); +#endif //RD_UI_TRANSITION_EFFECTS_LIST + MoveToItemIndexL(newIndex, aSelectionMode); + _AKNTRACE_FUNC_EXIT; + return; + } + + TInt oldRowIndex = rowIndex; + TInt oldColIndex = colIndex; + if (moveRight) + colIndex = 0; + else + colIndex = iGridDetails.iGridDimensions.iWidth - 1; + + if (moveDown) + rowIndex = 0; + else + rowIndex = iGridDetails.iGridDimensions.iHeight - 1; + + switch(scrollingType) + {// we are at an edge + case EScrollStops: + { + _AKNTRACE_FUNC_EXIT; + return; // easy + } + case EScrollFollowsGrid: + newIndex = SearchByLines((moveIsVert ? oldColIndex : colIndex),(moveIsVert ? rowIndex : oldRowIndex), aCursorMovement, ETrue); + break; + case EScrollFollowsItemsAndStops: + case EScrollFollowsItemsAndLoops: + newIndex = FindNextItem(iCurrentItemIndex, moveDown, moveRight, !IsPrimaryVertical()); + if (moveInPrim) + {// move in the primary direction of the grid + if (newIndex >=0) + { // found next item to move to +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + SetMoveType( iGc, aCursorMovement ); +#endif //RD_UI_TRANSITION_EFFECTS_LIST + MoveToItemIndexL(newIndex, aSelectionMode); + _AKNTRACE_FUNC_EXIT; + return; + } + // did not find anything + if (iScrollingType == EScrollFollowsItemsAndStops) + { + _AKNTRACE_FUNC_EXIT; + return; // do nothing + } + + // then must be EScrollFollowsItemsAndLoops + ListBoxIndexFromLogicalPos(newIndex, rowIndex, colIndex); + newIndex = FindNextItem(newIndex, moveDown, moveRight, !moveIsVert, ETrue); + } + else + {// move in scondary + if (newIndex < 0) + { // no more items + if (iScrollInSecondaryDimension == EScrollFollowsItemsAndStops) + { + _AKNTRACE_FUNC_EXIT; + return; + } + //must be EScrollFollowsItemsAndLoops + } + else + { // some more items before the end + if (moveIsVert) + { + if (moveRight) + colIndex = oldColIndex + 1; + else + colIndex = oldColIndex - 1; + } + else + { + if (moveDown) + rowIndex = oldRowIndex + 1; + else + rowIndex = oldRowIndex - 1; + } + } + newIndex = SearchByLines(colIndex, rowIndex, aCursorMovement, ETrue); + } + break; + case EScrollIncrementLineAndStops: + _AKNTRACE_FUNC_EXIT; + return; // do nothing + case EScrollIncrementLineAndLoops: + { + ListBoxIndexFromLogicalPos(newIndex, rowIndex, colIndex); + newIndex = FindNextItem(newIndex, moveDown, moveRight, !moveIsVert, ETrue); + if (!moveInPrim && newIndex >=0) + {// may need to have a special scroll + TBool specialMoveNeeded = EFalse; + LogicalPosFromListBoxIndex(newIndex, rowIndex, colIndex); + if (moveIsVert) + if ((rowIndex != 0) && (rowIndex != iGridDetails.iGridDimensions.iHeight - 1)) + specialMoveNeeded = ETrue; + else + if ((colIndex != 0) && (colIndex != iGridDetails.iGridDimensions.iWidth - 1)) + specialMoveNeeded = ETrue; + if (specialMoveNeeded) + {// first fake being at the far edge of the grid + if (moveRight) + colIndex = 0; + else + colIndex = iGridDetails.iGridDimensions.iWidth - 1; + + if (moveDown) + rowIndex = 0; + else + rowIndex = iGridDetails.iGridDimensions.iHeight - 1; + + TInt newIndex2 = 0; // fake index + ListBoxIndexFromLogicalPos(newIndex2, rowIndex, colIndex); + iTopItemIndex = CalcNewTopItemIndexSoItemIsVisible(newIndex2); + CalcBottomItemIndex(); + iCurrentItemIndex = newIndex; // set current to actual index we want to move to + iHScrollOffset += CalculateHScrollOffsetSoItemIsVisible(newIndex); + DrawItemRange(iTopItemIndex, iBottomItemIndex); // draw range for fake index + if (ItemIsVisible(newIndex)) + { + _AKNTRACE_FUNC_EXIT; + return; // moved and drawn + } + // need to scroll some more to make the newIndex visable + } + } + } + break; + default: + break; // should never get here + } + + if (newIndex >=0) + { // found next item to move to +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + SetMoveType( iGc, aCursorMovement ); +#endif //RD_UI_TRANSITION_EFFECTS_LIST + MoveToItemIndexL(newIndex, aSelectionMode); + } + _AKNTRACE_FUNC_EXIT; + } + +/** + * Used with grids which contain empty items + * returns the new listbox index of the next item + * returns -1 if there is nothing to move to. + */ +EXPORT_C TInt CAknGridView::SearchByLines(TInt aX, TInt aY, TCursorMovement aCursorMovement, TBool aBeginSearchOnIndex) + { + _AKNTRACE_FUNC_ENTER; + TInt xMax = iGridDetails.iGridDimensions.iWidth; + TInt yMax = iGridDetails.iGridDimensions.iHeight; + + TInt xIteration = 0; + TInt yIteration = 0; + switch(aCursorMovement) + { + case ECursorNextColumn: + xIteration = 1; + break; + case ECursorPreviousColumn: + xIteration = -1; + break; + case ECursorNextItem: + yIteration = 1; + break; + case ECursorPreviousItem: + yIteration = -1; + break; + default: + break; + } + // set up first for a Horizontal grid + TInt primaryIteration = xIteration; + TInt secondaryIteration = yIteration; + TInt primaryMax = xMax; + TInt secondaryMax = yMax; + TInt p = aX; + TInt s = aY; + // now change variables if it is a Vertical grid + if (IsPrimaryVertical()) + { + primaryIteration = yIteration; + secondaryIteration = xIteration; + primaryMax = yMax; + secondaryMax = xMax; + p = aY; + s = aX; + } + + if (!aBeginSearchOnIndex) + s += secondaryIteration; + + TInt index = 0; + for ( ; (s < secondaryMax) && (s >= 0) ; s += secondaryIteration) + { + for (TInt primaryOffset = 0;(p - primaryOffset >= 0) || (p + primaryOffset < primaryMax) ; primaryOffset++) + { + TInt x = 0; + TInt y = 0; + if (secondaryIteration == 0) + {// then we are moving in the primary orientation of the grid + // so just find the next item in this direction. + TInt offSet = (aBeginSearchOnIndex ? primaryOffset : primaryOffset+1); + x = p + (primaryIteration * (offSet)); + if (x < 0 || x >= primaryMax) + break; + y = s; + if (IsPrimaryVertical()) + {//swap them + y = x; + x = s; + } + DataIndexFromLogicalPos(index,y,x); + if (GridModel()->IndexContainsData(index)) + { + _AKNTRACE_FUNC_EXIT; + return ListBoxIndex(index); + } + } + else + { + TInt newOffset = p+(primaryOffset); + if ((newOffset >= 0) && (newOffset < primaryMax)) + { + x = newOffset; + y = s; + if (IsPrimaryVertical()) + { + x = s; + y = newOffset; + } + DataIndexFromLogicalPos(index,y,x); + if (GridModel()->IndexContainsData(index)) + { + _AKNTRACE_FUNC_EXIT; + return ListBoxIndex(index); + } + } + newOffset = p-(primaryOffset); + if ((newOffset >= 0) && (newOffset < primaryMax)) + { + x = newOffset; + y = s; + if (IsPrimaryVertical()) + { + x = s; + y = newOffset; + } + DataIndexFromLogicalPos(index,y,x); + if (GridModel()->IndexContainsData(index)) + { + _AKNTRACE_FUNC_EXIT; + return ListBoxIndex(index); + } + } + } + } + if (secondaryIteration == 0) + {// no more items + _AKNTRACE_FUNC_EXIT; + return -1; + } + } + _AKNTRACE_FUNC_EXIT; + // no more items + return -1; + } + +EXPORT_C TInt CAknGridView::FindNextItem(TInt aItemIndex, TBool aLookDown, TBool aLookRight, TBool aFirstLookHorizontal, TBool aBeginSearchOnIndex) + { + TInt newIndex = 0; + IsEdgePassed(aItemIndex, aLookDown, aLookRight, aFirstLookHorizontal, aBeginSearchOnIndex, newIndex); + return newIndex; + } + +TBool CAknGridView::IsEdgePassed(TInt aItemIndex, TBool aLookDown, TBool aLookRight, TBool aFirstLookHorizontal, TBool aBeginSearchOnIndex, TInt& aNewIndex) + { + _AKNTRACE_FUNC_ENTER; + TInt rowIndex = 0; + TInt colIndex = 0; + + LogicalPosFromListBoxIndex(aItemIndex, rowIndex, colIndex); + + TInt x = 0; + TInt y = 0; + TBool edgePassed = EFalse; + + CAknGridM* gridModel = GridModel(); + TInt newDataIndex = -1; + if (aFirstLookHorizontal) + { + x = (aBeginSearchOnIndex ? colIndex : (aLookRight ? colIndex + 1 : colIndex - 1)); + for (y = rowIndex; (y>=0) && (y < iGridDetails.iGridDimensions.iHeight); y = (aLookDown ? y+1 : y-1)) + { + for ( ; (x>=0) && (xIndexContainsData(newDataIndex)) + { + aNewIndex = ListBoxIndex(newDataIndex); + _AKNTRACE_FUNC_EXIT; + return edgePassed; + } + } + edgePassed = ETrue; + if (aLookRight) + x = 0; + else + x = iGridDetails.iGridDimensions.iWidth - 1; + } + } + else + { + y = (aBeginSearchOnIndex ? rowIndex : (aLookDown ? rowIndex + 1 : rowIndex - 1)); + for (x = colIndex; (x>=0) && (x < iGridDetails.iGridDimensions.iWidth); x = (aLookRight ? x+1 : x-1)) + { + for ( ; (y>=0) && (yIndexContainsData(newDataIndex)) + { + aNewIndex = ListBoxIndex(newDataIndex); + _AKNTRACE_FUNC_EXIT; + return edgePassed; + } + } + edgePassed = ETrue; + if (aLookDown) + y = 0; + else + y = iGridDetails.iGridDimensions.iHeight - 1; + } + } + + aNewIndex = -1; + _AKNTRACE_FUNC_EXIT; + return edgePassed; + } + + +TBool CAknGridView::IsMoveRight(TCursorMovement aCursorMovement) + { + _AKNTRACE_FUNC_ENTER; + TBool moveRight = EFalse; + switch(aCursorMovement) + { + case ECursorNextItem: + moveRight = COMPARE_BOOLS((iGridDetails.iGridFlags & ETopToBottom),(iGridDetails.iGridFlags & ELeftToRight)); + break; + case ECursorPreviousItem: + moveRight = !COMPARE_BOOLS((iGridDetails.iGridFlags & ETopToBottom),(iGridDetails.iGridFlags & ELeftToRight)); + break; + case ECursorNextColumn: + moveRight = ETrue; + break; + case ECursorPreviousColumn: + moveRight = EFalse; + break; + default: + break; + } + _AKNTRACE_FUNC_EXIT; + return moveRight; + } + +TBool CAknGridView::IsMoveDown(TCursorMovement aCursorMovement) + { + _AKNTRACE_FUNC_ENTER; + TBool moveDown = EFalse; + switch(aCursorMovement) + { + case ECursorNextItem: + moveDown = ETrue; + break; + case ECursorPreviousItem: + moveDown = EFalse; + break; + case ECursorNextColumn: + moveDown = COMPARE_BOOLS((iGridDetails.iGridFlags & ETopToBottom),(iGridDetails.iGridFlags & ELeftToRight)); + break; + case ECursorPreviousColumn: + moveDown = !COMPARE_BOOLS((iGridDetails.iGridFlags & ETopToBottom),(iGridDetails.iGridFlags & ELeftToRight)); + break; + default: + break; + } + _AKNTRACE_FUNC_EXIT; + return moveDown; + } + + +/** + * Overloaded MoveCursorL method to process cursor movement according to + * orientation of the grid. + */ +EXPORT_C void CAknGridView::MoveCursorL(TCursorMovement aCursorMovement, TSelectionMode aSelectionMode) + { + _AKNTRACE_FUNC_ENTER; + // This is driving method for all movement around the grid + + // check that actually some data in the grid + if (GridModel()->NumberOfData() == 0) + { + _AKNTRACE_FUNC_EXIT; + return; + } + +#if defined(_DEBUG) + switch (aCursorMovement) + { + // page movements + case ECursorFirstItem: // go back first index + MoveToItemIndexL(0, aSelectionMode); + _AKNTRACE_FUNC_EXIT; + return; + case ECursorLastItem: // go to last index + MoveToItemIndexL(GridModel()->IndexOfLastDataItem(), aSelectionMode); + _AKNTRACE_FUNC_EXIT; + return; + case ECursorNextPage: + MoveToItemIndexL((iCurrentItemIndex+iGridDetails.iPageSize < GridModel()->NumberOfData() ? iCurrentItemIndex+iGridDetails.iPageSize : GridModel()->NumberOfData() - 1), aSelectionMode); + _AKNTRACE_FUNC_EXIT; + return; + case ECursorPreviousPage: + MoveToItemIndexL((iCurrentItemIndex-iGridDetails.iPageSize >= 0 ? iCurrentItemIndex-iGridDetails.iPageSize : 0 ), aSelectionMode); + _AKNTRACE_FUNC_EXIT; + return; + default: + break; + } +#endif + // perform movement required + DoMoveL(aCursorMovement, aSelectionMode); + _AKNTRACE_FUNC_EXIT; + } + +/** + * Sets the width of the grid column. This should only be called via + * the selection box class's SetColumnWidth method. + */ +EXPORT_C void CAknGridView::SetColumnWidth(TInt aColumnWidth) + { + __ASSERT_ALWAYS((aColumnWidth > 0), Panic(EAknPanicGridViewInvalidItemWidth)); + + _AKNTRACE( " [%s] aColumnWidth = %d", + __FUNCTION__, aColumnWidth ); + iGridDetails.iSizeOfItems.iWidth = aColumnWidth; + + iItemDrawer->SetItemCellSize(ItemSize()); + } + +///////////////////////////////////////////////// +////////////////////////////////////////////////// + +EXPORT_C void CAknGridView::SetTopItemIndex(TInt aNewTopItemIndex) + { + _AKNTRACE( "[%s] aNewTopItemIndex = %d", + __FUNCTION__, aNewTopItemIndex ); + if (iViewRect.Height() == 0) + return; + CListBoxView::SetTopItemIndex(aNewTopItemIndex); + UpdateHScrollOffsetBasedOnTopItemIndex(); + } + +EXPORT_C void CAknGridView::SetItemHeight(TInt aItemHeight) + { + _AKNTRACE( "[%s] aItemHeight = %d", + __FUNCTION__, aItemHeight ); + CListBoxView::SetItemHeight(aItemHeight); + iGridDetails.iSizeOfItems.iHeight = aItemHeight; + CalcBottomItemIndex(); + UpdateHScrollOffsetBasedOnTopItemIndex(); + } + + +// --------------------------------------------------------------------------- +// Returns ETrue and sets aItemIndex to the index of the item whose +// bounding box contains aPosition, or EFalse if no such item exists. +// --------------------------------------------------------------------------- +// +EXPORT_C TBool CAknGridView::XYPosToItemIndex( TPoint aPosition, + TInt& aItemIndex ) const + { + _AKNTRACE_FUNC_ENTER; + TBool itemFound = EFalse; + + if ( ColumnWidth() == 0 || iItemHeight == 0 ) + { + return EFalse; + } + + if ( iViewRect.Contains( aPosition ) ) + { + // aPosition is inside the display area + TInt yOffsetFromViewRectOrigin = aPosition.iY - iViewRect.iTl.iY - iVerticalOffset; + TInt xOffsetFromViewRectOrigin = aPosition.iX - iViewRect.iTl.iX; + TInt xItemPlusGap = ColumnWidth() + iGridDetails.iSizeBetweenItems.iWidth; + TInt yItemPlusGap = iItemHeight + iGridDetails.iSizeBetweenItems.iHeight; + TInt colIndex = xOffsetFromViewRectOrigin / xItemPlusGap; + TInt rowIndex = yOffsetFromViewRectOrigin / yItemPlusGap; + TInt numberOfRowsInView = NumberOfRowsInView(); + + if ( yOffsetFromViewRectOrigin < 0 ) + { + rowIndex = -1; + } + else if ( yOffsetFromViewRectOrigin > iViewRect.Height() ) + { + // Ensure it will not go out of boundary... + rowIndex = Min( rowIndex, numberOfRowsInView); + } + + // If column or row is bigger than there are in view, + // then item is not found. + if ( colIndex >= NumberOfColsInView() || + rowIndex > numberOfRowsInView || + colIndex < 0 || + rowIndex < -1 ) + { + itemFound = EFalse; + } + else + { + // Need to take into account the gaps. + TInt yItemOffset = yOffsetFromViewRectOrigin % yItemPlusGap; + TInt xItemOffset = xOffsetFromViewRectOrigin % xItemPlusGap; + if ( yItemOffset > iItemHeight || xItemOffset > ColumnWidth() ) + { + _AKNTRACE_FUNC_EXIT; + return EFalse; + } + + // Now work out the item index given that we know which + // row and column it is in. + TInt itemIndex; + CalcItemIndexFromRowAndColIndexes( itemIndex, + rowIndex, + colIndex ); + + // Error correction that becomes tapping partially + // filled colour selection grid. + if ( ItemExists( itemIndex ) && + GridModel()->IndexContainsData( ActualDataIndex( itemIndex ) ) ) + { + aItemIndex = itemIndex; + itemFound = ETrue; + } + } + } + + _AKNTRACE_FUNC_EXIT; + return itemFound; + } + + +EXPORT_C void CAknGridView::CalcDataWidth() + { + iDataWidth = iGridDetails.iGridDimensions.iWidth; + } + +EXPORT_C TInt CAknGridView::VisibleWidth(const TRect& aRect) const + { + return aRect.Width() / ColumnWidth(); + } + + +// --------------------------------------------------------------------------- +// Scrolls the view so that the item with the given index becomes visible +// if it's currently outside of the view rectangle. +// --------------------------------------------------------------------------- +// +EXPORT_C TBool CAknGridView::ScrollToMakeItemVisible( TInt aItemIndex ) + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d", + __FUNCTION__, aItemIndex ); + if ( iViewRect.Height() == 0 || iItemHeight == 0 ) + { + _AKNTRACE_FUNC_EXIT; + return EFalse; + } + + const TBool redrawDisabled = RedrawDisabled(); + TPoint itemPosition( ItemPos( aItemIndex ) ); + TBool itemPartiallyVisible = ItemIsPartiallyVisible( aItemIndex ); + + if ( itemPartiallyVisible || ItemIsVisible( aItemIndex ) ) + { + _AKNTRACE_FUNC_EXIT; + // Item is already visible, so no scrolling required. + return EFalse; + } + + // Item is partially visible or not visible. + + HideMatcherCursor(); + TInt amountToScroll = CalculateHScrollOffsetSoItemIsVisible( aItemIndex ); + + if ( amountToScroll == 0 && !itemPartiallyVisible ) + { + _AKNTRACE_FUNC_EXIT; + return EFalse; + } + + iHScrollOffset += amountToScroll; + TBool gridVertical = IsPrimaryVertical(); + + // assume horizontal + TInt numOfLinesInViewOrientated = gridVertical ? NumberOfColsInView() : + NumberOfRowsInView(); + TInt numOfLinesInViewOrthogonal = gridVertical ? NumberOfRowsInView() : + NumberOfColsInView(); + + if ( Abs( amountToScroll ) >= numOfLinesInViewOrientated ) + { // Entire view content is changed, so don't bother scrolling. + iTopItemIndex += numOfLinesInViewOrthogonal * amountToScroll; + CalcBottomItemIndex(); + iCurrentItemIndex = aItemIndex; + iVerticalOffset = 0; + + if ( !redrawDisabled ) + { + Draw(); + DrawMatcherCursor(); + } + + _AKNTRACE_FUNC_EXIT; + return ETrue; + } + + iCurrentItemIndex = aItemIndex; + + if ( iExtension && !iExtension->iScrollingDisabled ) + { + CFormattedCellListBoxItemDrawer* itemDrawer = + static_cast( iItemDrawer ); + CEikListBox* listBox = + static_cast( + itemDrawer->FormattedCellData()->Control() ); + TRAP_IGNORE( listBox->HandlePhysicsScrollEventL( + amountToScroll * iItemHeight + ItemOffsetInPixels() ) ); + } + else + { + // Do normal scrolling if physics are not enabled. + VScrollTo( CalcNewTopItemIndexSoItemIsVisible( aItemIndex ) ); + } + + _AKNTRACE_FUNC_EXIT; + return ETrue; + } + + +////////////////////////////////////////////////// +EXPORT_C TInt CAknGridView::CalculateHScrollOffsetSoItemIsVisible(TInt aItemIndex) + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d", + __FUNCTION__, aItemIndex ); + // returns the number of cols or rows that we need to scroll, 0 if no scrolling is needed + TInt newTopItemIndex = CalcNewTopItemIndexSoItemIsVisible(aItemIndex); + TInt numToScroll = 0; + if (IsPrimaryVertical()) + { + TInt numOfRowsInView = NumberOfRowsInView(); + TInt oldHScrollOffset = iHScrollOffset; + TInt newHScrollOffset = newTopItemIndex / numOfRowsInView; + numToScroll = newHScrollOffset - oldHScrollOffset; + } + else + { + TInt logicalRow = 0; + TInt logicalCol = 0; + LogicalPosFromListBoxIndex(iTopItemIndex, logicalRow, logicalCol); + TInt oldHScrollOffset = logicalRow; + LogicalPosFromListBoxIndex(newTopItemIndex, logicalRow, logicalCol); + TInt newHScrollOffset = logicalRow; + numToScroll = newHScrollOffset - oldHScrollOffset; + } + _AKNTRACE_FUNC_EXIT; + return numToScroll; + } + +EXPORT_C TSize CAknGridView::ItemSize(TInt /*aItemIndex*/) const + { + return TSize(ColumnWidth(), iItemHeight); + } + + +EXPORT_C void CAknGridView::CalcRowAndColIndexesFromItemIndex( TInt aItemIndex, + TInt& aRowIndex, + TInt& aColIndex ) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d aRowIndex = %d aColIndex = %d", + __FUNCTION__, aItemIndex, aRowIndex, aColIndex ); + // Should panic if iItemHeight or iViewRect.Height() is 0. + // Assumes specified item is currently visible. + TInt numOfItemsFromFirstVisibleItem = (aItemIndex - iTopItemIndex); + + if ( IsPrimaryVertical() ) + { + TInt numOfRowsInView = NumberOfRowsInView(); + aColIndex = numOfItemsFromFirstVisibleItem / numOfRowsInView; + aRowIndex = numOfItemsFromFirstVisibleItem % numOfRowsInView; + } + else + { + TInt numOfColsInView = NumberOfColsInView(); + + if ( numOfItemsFromFirstVisibleItem < 0 ) + { + // This is possible the visible topmost row is partially drawn + // and iTopItemIndex has already moved to the next row. + // So this handling is required for the top row to be drawn + // correctly. + aColIndex = ( numOfItemsFromFirstVisibleItem + numOfColsInView ) % numOfColsInView; + aRowIndex = -1; + } + else + { + aColIndex = numOfItemsFromFirstVisibleItem % numOfColsInView; + aRowIndex = numOfItemsFromFirstVisibleItem / numOfColsInView; + } + } + _AKNTRACE_FUNC_EXIT; + } + + +// --------------------------------------------------------------------------- +// Calculates the item index that is on the given row and column indices. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknGridView::CalcItemIndexFromRowAndColIndexes( TInt& aItemIndex, + TInt aRowIndex, + TInt aColIndex ) const + { + _AKNTRACE_FUNC_ENTER; + _AKNTRACE( "[%s] aItemIndex = %d aRowIndex = %d aColIndex = %d", + __FUNCTION__, aItemIndex, aRowIndex, aColIndex ); + // Row index can be -1 if the row above top item index is partially + // visible. + __ASSERT_DEBUG( aRowIndex >= -1, Panic( EAknPanicGridViewInvalidRowIndex ) ); + __ASSERT_DEBUG( aColIndex >= 0, Panic( EAknPanicGridViewInvalidColumnIndex ) ); + + // Should panic if iItemHeight is 0. + if ( IsPrimaryVertical() ) + { + TInt numOfRowsInView = NumberOfRowsInView(); + aItemIndex = iTopItemIndex + ((aColIndex * numOfRowsInView) + aRowIndex); + } + else + { + TInt numOfColsInView = NumberOfColsInView(); + aItemIndex = iTopItemIndex + ((aRowIndex * numOfColsInView) + aColIndex); + } + _AKNTRACE_FUNC_EXIT; + } + + +EXPORT_C void CAknGridView::DrawMatcherCursor() + { + } + +// --------------------------------------------------------------------------- +// Returns the item index of the currently highlighted item. +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAknGridView::CurrentItemIndex() const + { + if ( ItemExists( iCurrentItemIndex ) ) + { + return iCurrentItemIndex; + } + else + { + // Means there is no current item. + return KErrNotFound; + } + } + +////////////////////////////////// protect + +// --------------------------------------------------------------------------- +// Draws a range of columns. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAknGridView::DrawColumnRange( TInt aStartColIndex, + TInt aEndColIndex ) const + { + _AKNTRACE_FUNC_ENTER; + if ( !RedrawDisabled() && iItemHeight > 0 ) + { + TInt numOfRowsInView = NumberOfRowsInView(); + TInt startItemIndex = aStartColIndex * numOfRowsInView; + TInt endItemIndex = aEndColIndex * numOfRowsInView + numOfRowsInView - 1; + DrawItemRange( startItemIndex, endItemIndex ); + } + _AKNTRACE_FUNC_EXIT; + } + + +EXPORT_C void CAknGridView::ClearUnusedItemSpace(TInt aStartItemIndex, TInt aEndItemIndex) const + { + _AKNTRACE_FUNC_ENTER; + TRect blankRect; + for (TInt i = aStartItemIndex; i <= aEndItemIndex; i++) + { + blankRect.SetRect(ItemPos(i), ItemSize()); + blankRect.Intersection(iViewRect); + + MAknsSkinInstance *skin = AknsUtils::SkinInstance(); + CFormattedCellListBoxItemDrawer *id = (CFormattedCellListBoxItemDrawer*)ItemDrawer(); + if (id->FormattedCellData()->Control()) + { + MAknsControlContext *cc = AknsDrawUtils::ControlContext( id->FormattedCellData()->Control() ); + if ( !cc ) + { + cc = id->FormattedCellData()->SkinBackgroundContext(); + } + AknsDrawUtils::Background( skin, cc, id->FormattedCellData()->Control(), *iGc, blankRect ); + } + else + { + iGc->Clear(blankRect); + } + } + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void CAknGridView::UpdateHScrollOffsetBasedOnTopItemIndex() + { + TInt numOfRowsInView = iGridDetails.iRowsInView; + if (numOfRowsInView > 0) + iHScrollOffset = iTopItemIndex / numOfRowsInView; + } + + +EXPORT_C TAny* CAknGridView::Reserved_1() + { + return NULL; + } + + +// --------------------------------------------------------------------------- +// Draws the part of the view rectangle in which no items are drawn. +// --------------------------------------------------------------------------- +// +void CAknGridView::DrawUnusedViewPortion() const + { + _AKNTRACE_FUNC_ENTER; + TInt gapWidth = iGridDetails.iSizeBetweenItems.iWidth; + TInt numberOfCols = iGridDetails.iColsInView; + TInt usedViewRectPortionWidth = + numberOfCols * ( ColumnWidth() + gapWidth ) - gapWidth; + TRect itemUsedRect; + //if the gapWidth > 0, the entire background should be drawn. + //So use default value of itemUsedRect (0,0,0,0). + //And vice versa the view rect except items used should + //draw background + if ( gapWidth <= 0 ) + { + TPoint endPos( CAknGridView::ItemPos( iBottomItemIndex ).iX + ColumnWidth(), + CAknGridView::ItemPos( iBottomItemIndex ).iY + iItemHeight ); + itemUsedRect.SetRect( CAknGridView::ItemPos(iTopItemIndex), endPos ); + if ( iViewRect.Intersects( itemUsedRect ) ) + { + TRect viewRect( iViewRect ); + viewRect.Intersection( itemUsedRect ); + } + } + iGc->SetBrushColor( BackColor() ); + CFormattedCellListBoxItemDrawer* itemDrawer = + static_cast( iItemDrawer ); + MAknsSkinInstance *skin = AknsUtils::SkinInstance(); + + CWindowGc* gc = itemDrawer->Gc(); + if ( !gc ) + { + gc = iGc; + } + + CCoeControl* listBoxControl = itemDrawer->FormattedCellData()->Control(); + + if ( listBoxControl ) + { + MAknsControlContext *cc = AknsDrawUtils::ControlContext( + listBoxControl ); + if ( !cc ) + { + cc = itemDrawer->FormattedCellData()->SkinBackgroundContext(); + } + + if ( CAknEnv::Static()->TransparencyEnabled() ) + { + AknsDrawUtils::BackgroundBetweenRects( + skin, + cc, + listBoxControl, + *iGc, + iViewRect, + itemUsedRect, + KAknsDrawParamNoClearUnderImage ); + } + else + { + AknsDrawUtils::BackgroundBetweenRects( + skin, + cc, + listBoxControl, + *iGc, + iViewRect, + itemUsedRect ); + } + } + else + { + DrawUtils::ClearBetweenRects( *gc, iViewRect, itemUsedRect ); + } + _AKNTRACE_FUNC_EXIT; + } + +// End of File