/*
* Copyright (c) 1997-2010 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:
*
*/
#include <badesca.h>
#include <gdi.h>
#include <w32std.h>
#include <eiklbx.pan>
#include <eiklbx.h>
#include <eiklbv.h>
#include <eiklbm.h>
#include <eiklbi.h>
#include <gulutil.h>
#include <eikenv.h>
#include <avkon.rsg>
#include <barsread.h>
#include <AknUtils.h>
#include <AknsDrawUtils.h>
#include <AknsControlContext.h>
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
#include <aknlistboxtfxinternal.h>
#include <aknlistloadertfx.h>
#endif
#include "laflbv.h"
#include "laflbx.h"
#include "akntrace.h"
#define ITEM_EXISTS_BEGIN TInt no_of_items__ = iModel->NumberOfItems()
#define ITEM_EXISTS(x) (((x) > -1) && ((x) < no_of_items__))
#define ITEM_EXISTS_ONCE(x) (((x) > -1) && ((x) < iModel->NumberOfItems()))
//
// class CListBoxView
//
CListBoxViewExtension* CListBoxViewExtension::NewL()
{
CListBoxViewExtension* self = new ( ELeave ) CListBoxViewExtension;
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
CListBoxViewExtension::~CListBoxViewExtension()
{
}
void CListBoxViewExtension::ConstructL()
{
// Panning and flicking disabled by default
iScrollingDisabled = ETrue;
}
void CListBoxView::SetVisibilityObserver(MListVisibilityObserver* aObserver)
{
iVisibilityObserver=aObserver;
}
EXPORT_C TBool CListBoxView::IsVisible() const
{
if(iVisibilityObserver)
return(iVisibilityObserver->IsVisible());
return ETrue;
}
EXPORT_C void CListBoxView::SetListEmptyTextL(const TDesC& aText)
{
delete iListEmptyText;
iListEmptyText = NULL;
iListEmptyText= aText.AllocL();
}
EXPORT_C CListBoxView::CListBoxView()
{
_AKNTRACE_FUNC_ENTER;
iItemHeight = 20;
// iBackColor = KDefaultLbxBackColor;
iBackColor = CEikonEnv::Static()->Color(EColorControlBackground); //KDefaultLbxBackColor;
iMatcherCursorColor = TRgb(177, 177, 177); // light gray?
iCurrentItemIndex = 0;
iTopItemIndex = 0;
iListEmptyText = 0;
iVerticalOffset = 0;
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::ConstructL(MListBoxModel* aList, CListItemDrawer* aItemDrawer, CWsScreenDevice* aScreen, RWindowGroup* aGroupWindow, RWindow* aWsWindow, const TRect& aDisplayArea, TInt aItemHeight)
{
_AKNTRACE_FUNC_ENTER;
iExtension = CListBoxViewExtension::NewL();
iModel = aList;
iItemDrawer = aItemDrawer;
iWin = aWsWindow;
iGroupWin = aGroupWindow;
// create a graphics context
User::LeaveIfError(aScreen->CreateContext(iGc));
iGc->Activate(*iWin);
iItemDrawer->SetGc(iGc);
iViewRect = aDisplayArea;
iItemHeight = aItemHeight;
iSelectionIndexes = new(ELeave) CArrayFixFlat<TInt>(5);
//SetListEmptyTextL(_L("No Data"));
TResourceReader rr;
CEikonEnv::Static()->CreateResourceReaderLC(rr,R_AVKON_LISTBOX_DEFAULT_EMPTY_TEXT);
TPtrC emptytext= rr.ReadTPtrC();
SetListEmptyTextL(emptytext);
CleanupStack::PopAndDestroy();
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C CListBoxView::~CListBoxView()
{
_AKNTRACE_FUNC_ENTER;
// Although my "item Drawer" is created by some other object, it is convenient
// for me to destroy it here...
delete iExtension;
delete(iItemDrawer);
delete iSelectionIndexes;
delete(iGc);
delete (iListEmptyText);
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TInt CListBoxView::TopItemIndex() const
{
_AKNTRACE( "iTopItemIndex = %d", iTopItemIndex );
return iTopItemIndex;
}
EXPORT_C TInt CListBoxView::BottomItemIndex() const
{
_AKNTRACE( "iBottomItemIndex = %d", iBottomItemIndex );
return iBottomItemIndex;
}
EXPORT_C TBool CListBoxView::ItemIsSelected(TInt aItemIndex) const
{
_AKNTRACE( "Item selected is %d", aItemIndex );
TKeyArrayFix key(0, ECmpTInt);
TInt pos;
if (iSelectionIndexes->Find(aItemIndex, key, pos))
return(EFalse);
return(ETrue);
}
EXPORT_C void CListBoxView::ToggleItemL(TInt aItemIndex)
{
_AKNTRACE_FUNC_ENTER;
__ASSERT_DEBUG(iSelectionIndexes, Panic(EEikPanicListBoxNoSelIndexArray));
if (iItemDrawer->Properties(aItemIndex).IsSelectionHidden()) { DeselectItem(aItemIndex); return; }
TKeyArrayFix key(0, ECmpTInt);
TInt pos;
if (iSelectionIndexes->Find(aItemIndex, key, pos))
iSelectionIndexes->AppendL(aItemIndex);
else
iSelectionIndexes->Delete(pos);
DrawItem(aItemIndex);
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::SelectItemL(TInt aItemIndex)
{
// select the specified item; if already selected, do nothing
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "SelectItem is %d", aItemIndex );
__ASSERT_DEBUG(iSelectionIndexes, Panic(EEikPanicListBoxNoSelIndexArray));
if (iItemDrawer->Properties(aItemIndex).IsSelectionHidden())
{
DeselectItem(aItemIndex);
_AKNTRACE_FUNC_EXIT;
return;
}
TKeyArrayFix key(0, ECmpTInt);
TInt pos;
if (iSelectionIndexes->Find(aItemIndex, key, pos))
{
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iGc );
if ( transApi )
{
transApi->Invalidate( MAknListBoxTfxInternal::EListItem, aItemIndex );
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
iSelectionIndexes->AppendL(aItemIndex);
DrawItem(aItemIndex);
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::DeselectItem(TInt aItemIndex)
{
// deselect the specified item; if not currently selected, do nothing
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "DeselectItem is %d", aItemIndex );
__ASSERT_DEBUG(iSelectionIndexes, Panic(EEikPanicListBoxNoSelIndexArray));
TKeyArrayFix key(0, ECmpTInt);
TInt pos;
if (!(iSelectionIndexes->Find(aItemIndex, key, pos)))
{
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iGc );
if ( transApi )
{
transApi->Invalidate( MAknListBoxTfxInternal::EListItem, aItemIndex );
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
iSelectionIndexes->Delete(pos);
DrawItem(aItemIndex);
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::GetSelectionIndexesL(CSelectionIndexArray *aSelectionArray) const
{
__ASSERT_DEBUG(aSelectionArray, Panic(EEikPanicListBoxInvalidSelIndexArraySpecified));
__ASSERT_DEBUG(iSelectionIndexes, Panic(EEikPanicListBoxNoSelIndexArray));
aSelectionArray->Reset();
TInt selectionIndex;
TInt numOfSelections = iSelectionIndexes->Count();
for (TInt i = 0; i < numOfSelections; i++)
{
selectionIndex = (*(iSelectionIndexes))[i];
aSelectionArray->AppendL(selectionIndex);
}
}
EXPORT_C void CListBoxView::SetSelectionIndexesL(const CSelectionIndexArray *aSelectionArray)
{
__ASSERT_DEBUG(aSelectionArray, Panic(EEikPanicListBoxInvalidSelIndexArraySpecified));
ClearSelection();
TInt numOfSelections = aSelectionArray->Count();
TInt selectionIndex;
for (TInt i = 0; i < numOfSelections; i++)
{
selectionIndex = (*aSelectionArray)[i];
SelectItemL(selectionIndex);
}
}
EXPORT_C const CListBoxView::CSelectionIndexArray* CListBoxView::SelectionIndexes() const
{
return iSelectionIndexes;
}
EXPORT_C void CListBoxView::ClearSelection()
{
_AKNTRACE_FUNC_ENTER;
__ASSERT_DEBUG(iSelectionIndexes, Panic(EEikPanicListBoxNoSelIndexArray));
TInt numSelectedItems = iSelectionIndexes->Count();
TInt selectedItemIndex;
for (TInt i = 0; i < numSelectedItems; i++)
{
selectedItemIndex = (*(iSelectionIndexes))[0];
DeselectItem(selectedItemIndex);
}
ClearSelectionAnchorAndActiveIndex();
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::ClearSelectionAnchorAndActiveIndex()
{
_AKNTRACE_FUNC_ENTER;
iAnchorIndex = 0;
iActiveEndIndex = 0;
ClearFlags(EAnchorExists);
ClearFlags(EMarkSelection);
ClearFlags(EUnmarkSelection);
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::SelectRangeL(TInt aItemIndex1, TInt aItemIndex2)
{
TInt startItem, endItem;
startItem = Min(aItemIndex1, aItemIndex2);
endItem = Max(aItemIndex1, aItemIndex2);
for (TInt i = startItem; i <= endItem; i++)
SelectItemL(i);
}
EXPORT_C void CListBoxView::SetAnchor(TInt aItemIndex)
{
SetFlags(EAnchorExists);
iAnchorIndex = aItemIndex;
iActiveEndIndex = aItemIndex;
}
EXPORT_C void CListBoxView::UpdateSelectionL(TSelectionMode aSelectionMode)
{
// assumes that iCurrentItemIndex has already been updated...
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "aSelectionMode is %d", aSelectionMode );
if (iCurrentItemIndex == -1) // i.e. no selection
{
ClearSelection();
_AKNTRACE_FUNC_EXIT;
return;
}
TInt newActiveEndIndex = iCurrentItemIndex;
if ( Flags() & EPaintedSelection )
{
switch (aSelectionMode)
{
case ENoSelection:
{
ClearFlags(EAnchorExists);
iActiveEndIndex = iCurrentItemIndex;
DrawItem(iCurrentItemIndex);
break;
}
case ESingleSelection:
{
TInt i = 0;
iAnchorIndex = iCurrentItemIndex;
iActiveEndIndex = iCurrentItemIndex;
SetFlags(EAnchorExists);
TInt selectedItemIndex;
while (i < iSelectionIndexes->Count())
{
selectedItemIndex = (*(iSelectionIndexes))[i];
DeselectItem(selectedItemIndex);
}
//DrawItem(iActiveEndIndex);
SelectItemL(newActiveEndIndex);
}
break;
case EContiguousSelection:
{
if (newActiveEndIndex == iActiveEndIndex)
break;
if (!(iFlags & EAnchorExists))
{
iAnchorIndex = newActiveEndIndex;
SetFlags(EAnchorExists);
}
TInt startIndex=0, endIndex=0;
if ( iActiveEndIndex < newActiveEndIndex )
{
startIndex = iActiveEndIndex;
endIndex = newActiveEndIndex; // - 1; // select current item too
}
else
{
startIndex = newActiveEndIndex; // + 1; // select current item too
endIndex = iActiveEndIndex;
}
SelectRangeL( startIndex, endIndex ); // select always
iActiveEndIndex = iCurrentItemIndex;
DrawItem(iActiveEndIndex);
}
break;
case EDisjointSelection:
ClearFlags(EAnchorExists);
ToggleItemL(newActiveEndIndex);
iActiveEndIndex = iCurrentItemIndex;
break;
default:
break;
}
}
else // Here begins the Eikon original code
{
switch (aSelectionMode)
{
case ENoSelection:
DrawItem(iCurrentItemIndex);
break;
case ESingleSelection:
{
TInt i = 0;
iAnchorIndex = newActiveEndIndex;
iActiveEndIndex = newActiveEndIndex;
SetFlags(EAnchorExists);
TInt selectedItemIndex;
// deselect everything except newActiveEndIndex
while (i < iSelectionIndexes->Count())
{
selectedItemIndex = (*(iSelectionIndexes))[i];
DeselectItem(selectedItemIndex);
}
SelectItemL(newActiveEndIndex);
}
break;
case EContiguousSelection:
{
TInt itemIndex=0;
if (newActiveEndIndex == iActiveEndIndex)
break;
if (!(iFlags & EAnchorExists))
{
iAnchorIndex = newActiveEndIndex;
iActiveEndIndex = newActiveEndIndex;
SetFlags(EAnchorExists);
SelectRangeL(iAnchorIndex, newActiveEndIndex);
break;
}
if ((newActiveEndIndex < iActiveEndIndex) && (iActiveEndIndex <= iAnchorIndex))
SelectRangeL(iActiveEndIndex, newActiveEndIndex);
else if ((newActiveEndIndex < iActiveEndIndex) && (iActiveEndIndex > iAnchorIndex))
{
itemIndex = iActiveEndIndex;
while ((itemIndex > newActiveEndIndex) && (itemIndex > iAnchorIndex))
{
DeselectItem(itemIndex);
--itemIndex;
}
SelectRangeL(iAnchorIndex, newActiveEndIndex);
}
else if ((newActiveEndIndex > iActiveEndIndex) && (iActiveEndIndex < iAnchorIndex))
{
itemIndex = iActiveEndIndex;
while ((itemIndex < newActiveEndIndex) && (itemIndex < iAnchorIndex))
{
DeselectItem(itemIndex);
++itemIndex;
}
SelectRangeL(iAnchorIndex, newActiveEndIndex);
}
else if ((newActiveEndIndex > iActiveEndIndex) && (iActiveEndIndex >= iAnchorIndex))
SelectRangeL(iActiveEndIndex, newActiveEndIndex);
iActiveEndIndex = newActiveEndIndex;
DrawItem(iActiveEndIndex);
}
break;
case EDisjointSelection: // toggled behavior
// Make a choice whether to mark or unmark
// We havent made that choice yet.
if (!ItemIsSelected(newActiveEndIndex))
{
SetFlags(EMarkSelection);
ClearFlags(EUnmarkSelection);
}
else
{
SetFlags(EUnmarkSelection);
ClearFlags(EMarkSelection);
}
if (newActiveEndIndex == iActiveEndIndex)
{
ClearFlags(EAnchorExists);
ToggleItemL(newActiveEndIndex);
break;
}
iAnchorIndex = newActiveEndIndex;
iActiveEndIndex = newActiveEndIndex;
SetFlags(EAnchorExists);
ToggleItemL(newActiveEndIndex);
break;
case EDisjointMarkSelection: // can only mark items, not unmark them
// Make a choice whether to mark or unmark
if (! (Flags()&EMarkSelection ||Flags()&EUnmarkSelection))
{
// We havent made that choice yet.
if (ItemIsSelected(iAnchorIndex))
{
ClearFlags(EMarkSelection);
SetFlags(EUnmarkSelection);
}
else
{
ClearFlags(EUnmarkSelection);
SetFlags(EMarkSelection);
}
}
// order of these is important.
if (Flags()&EMarkSelection)
SelectItemL(iActiveEndIndex);
else
DeselectItem(iActiveEndIndex);
//iAnchorIndex = newActiveEndIndex;
iActiveEndIndex = newActiveEndIndex;
//SetFlags(EAnchorExists);
if (Flags()&EMarkSelection)
SelectItemL(newActiveEndIndex);
else
DeselectItem(newActiveEndIndex);
DrawItem(iCurrentItemIndex);
break;
case EChangeMarkMode:
{
// Clear flags, correct flag will be set on later.
ClearFlags(EMarkSelection);
ClearFlags(EUnmarkSelection);
// If item is hidden, use next non-hidden item to decide markmode.
while( iItemDrawer->Properties(newActiveEndIndex).IsSelectionHidden()
&& newActiveEndIndex != iActiveEndIndex )
{
if ( newActiveEndIndex > iActiveEndIndex )
{
newActiveEndIndex--;
}
else
{
newActiveEndIndex++;
}
}
// Change Mark Mode to different than current mark is
if (ItemIsSelected(newActiveEndIndex))
{
SetFlags(EUnmarkSelection);
}
else
{
SetFlags(EMarkSelection);
}
}
break;
case EPenMultiselection:
{
TInt itemIndex=0;
TBool mark = (Flags() & EMarkSelection);
if ((newActiveEndIndex < iActiveEndIndex) && (iActiveEndIndex <= iAnchorIndex))
{
if ( mark )
{
SelectRangeL(iActiveEndIndex, newActiveEndIndex);
}
else
{
DeselectRangeL(iActiveEndIndex, newActiveEndIndex);
}
}
else if ((newActiveEndIndex < iActiveEndIndex) && (iActiveEndIndex > iAnchorIndex))
{
itemIndex = iActiveEndIndex;
while ((itemIndex > newActiveEndIndex) && (itemIndex > iAnchorIndex))
{
if ( mark )
{
DeselectItem(itemIndex);
}
else
{
SelectItemL(itemIndex);
}
--itemIndex;
}
if ( mark )
{
SelectRangeL(iAnchorIndex, newActiveEndIndex);
}
else
{
DeselectRangeL(iAnchorIndex, newActiveEndIndex);
}
}
else if ((newActiveEndIndex > iActiveEndIndex) && (iActiveEndIndex < iAnchorIndex))
{
itemIndex = iActiveEndIndex;
while ((itemIndex < newActiveEndIndex) && (itemIndex < iAnchorIndex))
{
if ( mark )
{
DeselectItem(itemIndex);
}
else
{
SelectItemL(itemIndex);
};
++itemIndex;
}
if ( mark )
{
SelectRangeL(iAnchorIndex, newActiveEndIndex);
}
else
{
DeselectRangeL(iAnchorIndex, newActiveEndIndex);
}
}
// "=" is necessary for Editkey + sigle tab on an item
else if ((newActiveEndIndex >= iActiveEndIndex) && (iActiveEndIndex >= iAnchorIndex))
{
if ( mark )
{
SelectRangeL(iActiveEndIndex, newActiveEndIndex);
}
else
{
DeselectRangeL(iAnchorIndex, newActiveEndIndex);
}
}
iActiveEndIndex = newActiveEndIndex;
DrawItem(iActiveEndIndex);
break;
}
default:
break;
}
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::CalcBottomItemIndex()
/* called by listbox control when either the size of the listbox or the number of items in
its model changes
*/
{
_AKNTRACE_FUNC_ENTER;
TInt i = iTopItemIndex;
TInt totalHeight = 0;
TInt numberOfVisibleItems = 0;
// iVerticalOffset is negative (add this to view's height)
TInt viewHeight = iViewRect.Height();
viewHeight -= iVerticalOffset;
ITEM_EXISTS_BEGIN;
while ((totalHeight < viewHeight) && (ITEM_EXISTS(i)))
{
totalHeight += iItemHeight;
++ i;
++ numberOfVisibleItems;
}
iBottomItemIndex = Max(0, iTopItemIndex + numberOfVisibleItems - 1);
_AKNTRACE( "iBottomItemIndex is %d", iBottomItemIndex );
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TInt CListBoxView::NumberOfItemsThatFitInRect(const TRect& aRect) const
{
TInt itemNumber = 0;
if (iItemHeight == 0)
{
_AKNTRACE( "Number of items is 0" );
return itemNumber;
}
TInt items = aRect.Height() / iItemHeight;
TInt extraHeight = aRect.Height() % iItemHeight;
// if there is offset or extra height, then there is at least one partical
// displayed item
if ( iVerticalOffset != 0 || extraHeight > 0 )
{
items++;
}
// if extra height is not totally taken by top partically displayed item,
// then there is still place to display a partcial item in bottom. consider
// a example which view height is 35 and item height is 10, then it's possible
// to display 5 items with the height like 3,10,10,10,2
if ( iVerticalOffset != 0 &&
extraHeight != 0 &&
( iItemHeight + iVerticalOffset ) < extraHeight )
{
items++;
}
itemNumber = items;
_AKNTRACE( "Number of items is %d", itemNumber );
return itemNumber;
}
EXPORT_C void CListBoxView::DeselectRangeL(TInt aItemIndex1, TInt aItemIndex2)
{
TInt startItem, endItem;
startItem = Min(aItemIndex1, aItemIndex2);
endItem = Max(aItemIndex1, aItemIndex2);
for (TInt i = startItem; i <= endItem; i++)
{
DeselectItem(i);
}
}
EXPORT_C TBool CListBoxView::ItemIsVisible(TInt aItemIndex) const
{
if ((aItemIndex == 0) && !(ITEM_EXISTS_ONCE(aItemIndex)))
return EFalse;
return ((aItemIndex >= iTopItemIndex) && (aItemIndex <= iBottomItemIndex));
}
EXPORT_C TPoint CListBoxView::ItemPos(TInt aItemIndex) const
{
return TPoint(-iHScrollOffset + iViewRect.iTl.iX, iViewRect.iTl.iY +
(aItemIndex - iTopItemIndex) * iItemHeight + iVerticalOffset);
}
EXPORT_C TSize CListBoxView::ItemSize(TInt /*aItemIndex*/) const
{
/*This return value controls the actual size of item which the text may
or may not be clipped and truncated with an ellipse to fit into*/
return TSize(LafListBoxView::ItemWidth(iViewRect.Width(), DataWidth()), iItemHeight);
}
EXPORT_C TBool CListBoxView::XYPosToItemIndex(TPoint aPosition, TInt& aItemIndex) const
{
// returns ETrue and sets aItemIndex to the index of the item whose bounding box contains aPosition
// returns EFalse if no such item exists
_AKNTRACE_FUNC_ENTER;
TBool itemFound = EFalse;
if (iItemHeight == 0)
{
_AKNTRACE_FUNC_EXIT;
return EFalse;
}
if (iViewRect.Contains(aPosition))
{
// aPosition is inside the display area
TInt yOffsetFromViewRectOrigin = aPosition.iY - iViewRect.iTl.iY - iVerticalOffset;
TInt numberOfItemsFromTheTop = yOffsetFromViewRectOrigin / iItemHeight;
TInt itemAtSpecifiedPos = iTopItemIndex + numberOfItemsFromTheTop;
if (ITEM_EXISTS_ONCE(itemAtSpecifiedPos))
{
aItemIndex = itemAtSpecifiedPos;
itemFound = ETrue;
}
}
_AKNTRACE_FUNC_EXIT;
return itemFound;
}
EXPORT_C void CListBoxView::MoveCursorL(TCursorMovement aCursorMovement, TSelectionMode aSelectionMode)
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "aSelectionMode is %d", aSelectionMode );
TInt pageSize = NumberOfItemsThatFitInRect(iViewRect);
TInt numOfItems = iModel->NumberOfItems();
switch (aCursorMovement)
{
case ECursorNextItem:
VerticalMoveToItemL(iCurrentItemIndex + 1, aSelectionMode);
break;
case ECursorPreviousItem:
VerticalMoveToItemL(iCurrentItemIndex - 1, aSelectionMode);
break;
case ECursorNextPage:
VerticalMoveToItemL(iCurrentItemIndex + Min((pageSize - 1), numOfItems - 1 - iCurrentItemIndex),
aSelectionMode);
break;
case ECursorPreviousPage:
VerticalMoveToItemL(iCurrentItemIndex - Min((pageSize - 1), iCurrentItemIndex),
aSelectionMode);
break;
case ECursorFirstItem:
VerticalMoveToItemL(0, aSelectionMode);
break;
case ECursorLastItem:
if (numOfItems > 0)
VerticalMoveToItemL(numOfItems-1, aSelectionMode);
break;
case ECursorNextScreen:
{
TInt targetItem = iTopItemIndex + pageSize;
if (targetItem > numOfItems - pageSize) targetItem = numOfItems - pageSize;
if (targetItem < 0) targetItem = 0;
VScrollTo(targetItem);
SetCurrentItemIndex(targetItem);
}
break;
case ECursorPrevScreen:
{
TInt targetItem = iTopItemIndex - pageSize;
if (targetItem < 0) targetItem = 0;
VScrollTo(targetItem);
SetCurrentItemIndex(targetItem);
}
break;
default:
break;
};
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::VerticalMoveToItemL(TInt aTargetItemIndex, TSelectionMode aSelectionMode)
{
// SERIES60 IMPLEMENTATION
_AKNTRACE_FUNC_ENTER;
if (ITEM_EXISTS_ONCE(aTargetItemIndex))
{
TInt oldCurrentItemIndex = iCurrentItemIndex;
iCurrentItemIndex = aTargetItemIndex;
TInt oldVerticalOffset = iVerticalOffset;
TInt newTopItemIndex = CalcNewTopItemIndexSoItemIsVisible(aTargetItemIndex);
if ( oldVerticalOffset != iVerticalOffset )
{
iFlags |= EOffsetChanged;
}
TInt oldVOffset = oldCurrentItemIndex - iTopItemIndex;
TInt newVOffset = aTargetItemIndex - newTopItemIndex;
// We calculate if the change in highlight position moves highlight in screen
TBool sameHighlightPos = oldVOffset == newVOffset;
// When a partially visible item gets focus, it should be fully visible.
// 'iFlags & EOffsetChanged' can be use to judge in this case.
if ((ItemIsVisible(iCurrentItemIndex)) && !(iFlags & EOffsetChanged))
{
if (!sameHighlightPos &&
(!ItemIsSelected(oldCurrentItemIndex) ||
aSelectionMode != ESingleSelection))
{
DrawItem(oldCurrentItemIndex);
}
}
else // items will get redrawn anyway
{
// As the iVerticalOffset is changed in CalcNewTopItemIndexSoItemIsVisible(),
// and ScrollToMakeItemVisible() will call the CalcNewTopItemIndexSoItemIsVisible() again,
// which will use iVerticalOffset to do some judgementes,
// we must set iVerticalOffset back to original value.
iVerticalOffset = oldVerticalOffset;
ScrollToMakeItemVisible(iCurrentItemIndex);
}
UpdateSelectionL(aSelectionMode);
iFlags &= ~EOffsetChanged;
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::VScrollTo(TInt aNewTopItemIndex)
{
_AKNTRACE_FUNC_ENTER;
if (iTopItemIndex == aNewTopItemIndex && !(iFlags & EOffsetChanged))
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (RedrawDisabled())
{
SetTopItemIndex(aNewTopItemIndex);
_AKNTRACE_FUNC_EXIT;
return;
}
TRect minRedrawRect;
HideMatcherCursor();
VScrollTo(aNewTopItemIndex, minRedrawRect);
if (ItemIsVisible(iCurrentItemIndex))
DrawMatcherCursor();
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::VScrollTo(TInt aNewTopItemIndex, TRect& aMinRedrawRect)
{
_AKNTRACE_FUNC_ENTER;
if (iTopItemIndex == aNewTopItemIndex && !(iFlags & EOffsetChanged))
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (RedrawDisabled())
{
SetTopItemIndex(aNewTopItemIndex);
_AKNTRACE_FUNC_EXIT;
return;
}
aMinRedrawRect.SetRect(iViewRect.iTl,iViewRect.Size());
SetTopItemIndex(aNewTopItemIndex);
Draw(&aMinRedrawRect);
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::HScroll(TInt aHScrollAmount)
{
_AKNTRACE_FUNC_ENTER;
if (RedrawDisabled())
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (aHScrollAmount == 0)
{
_AKNTRACE_FUNC_EXIT;
return;
}
TInt maxNumOfPixelsScrolledRight = DataWidth() - VisibleWidth(iViewRect);
if (maxNumOfPixelsScrolledRight <= 0)
{
_AKNTRACE_FUNC_EXIT;
return;
}
TInt oldHScrollOffset = iHScrollOffset;
iHScrollOffset += aHScrollAmount;
iHScrollOffset = Max(0, Min(iHScrollOffset, maxNumOfPixelsScrolledRight));
DrawMatcherCursor();
TInt actualScrollAmount = iHScrollOffset - oldHScrollOffset;
iWin->Scroll(iViewRect, TPoint(-actualScrollAmount, 0));
TRect redrawRect(iViewRect.iTl+TPoint(iViewRect.Width()-actualScrollAmount,0),TSize(actualScrollAmount,iViewRect.Height()));
if (actualScrollAmount<0)
redrawRect.SetRect(iViewRect.iTl,TSize(-actualScrollAmount,iViewRect.Height()));
redrawRect.Intersection(iViewRect);
iItemDrawer->Gc()->Clear( redrawRect );
iWin->Invalidate(redrawRect);
iWin->BeginRedraw(redrawRect);
Draw(&redrawRect);
iWin->EndRedraw();
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TInt CListBoxView::HScrollOffset() const
{
return iHScrollOffset;
}
EXPORT_C void CListBoxView::SetHScrollOffset(TInt aHScrollOffset)
{
iHScrollOffset = aHScrollOffset;
}
EXPORT_C void CListBoxView::SetItemHeight(TInt aItemHeight)
{
_AKNTRACE_FUNC_ENTER;
_AKNTRACE( "aItemHeight is %d", aItemHeight );
SetItemOffsetInPixels( 0 );
iItemHeight = aItemHeight;
iItemDrawer->SetItemCellSize(ItemSize());
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::SetViewRect(const TRect& aRect)
{
if ( aRect != iViewRect && iViewRect != TRect::EUninitialized )
{
iGc->Deactivate();
iGc->Activate( *iWin );
}
iViewRect = aRect;
iItemDrawer->SetViewRect(iViewRect);
iItemDrawer->SetItemCellSize(ItemSize());
}
EXPORT_C TRect CListBoxView::ViewRect() const
{
return iViewRect;
}
EXPORT_C void CListBoxView::DrawItem(TInt aItemIndex) const
{
_AKNTRACE_FUNC_ENTER;
if (RedrawDisabled() || !IsVisible())
{
_AKNTRACE_FUNC_EXIT;
return;
}
if ((ITEM_EXISTS_ONCE(aItemIndex)) && ItemIsVisible(aItemIndex))
{
TBool drawingInitiated = ETrue;
if ( iWin && iWin->GetDrawRect() == TRect::EUninitialized )
{
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
MAknListBoxTfxInternal* transApi =
CAknListLoader::TfxApiInternal( iGc );
drawingInitiated = transApi && !transApi->EffectsDisabled();
#else
drawingInitiated = EFalse;
#endif
}
if ( !drawingInitiated )
{
TRect rect( ItemPos(aItemIndex), iItemDrawer->ItemCellSize() );
rect.Intersection( iViewRect );
iWin->Invalidate( rect );
iWin->BeginRedraw( rect );
}
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iGc );
if ( transApi )
{
TRect rect( ItemPos( aItemIndex ),
ItemSize(aItemIndex) );
transApi->BeginRedraw( MAknListBoxTfxInternal::EListItem, rect, aItemIndex );
transApi->StartDrawing( MAknListBoxTfxInternal::EListItem );
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
TBool backgroundDrawingSuppressed = ( iItemDrawer
&& ( iItemDrawer->Flags()
& ( CListItemDrawer::EDrawWholeBackground
| CListItemDrawer::EBackgroundDrawn ) ) );
if ( !backgroundDrawingSuppressed )
{
iGc->SetClippingRect( iViewRect );
}
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
if ( transApi )
{
transApi->StopDrawing();
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
TBool currentItem = (aItemIndex == iCurrentItemIndex);
iItemDrawer->DrawItem(aItemIndex, ItemPos(aItemIndex), ItemIsSelected(aItemIndex),
currentItem, (iFlags&EEmphasized)>0, (iFlags&EDimmed)>0 );
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
if ( transApi )
{
transApi->StartDrawing( MAknListBoxTfxInternal::EListItem );
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
if ( !backgroundDrawingSuppressed )
{
iGc->CancelClippingRect();
}
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
if ( transApi )
{
transApi->StopDrawing();
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
if ( transApi )
{
transApi->EndRedraw( MAknListBoxTfxInternal::EListItem, aItemIndex );
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
if ( !drawingInitiated )
{
iWin->EndRedraw();
}
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::Draw( const TRect* /*aClipRect*/ ) const
{
_AKNTRACE_FUNC_ENTER;
if ( RedrawDisabled() || !IsVisible() )
{
_AKNTRACE_FUNC_EXIT;
return;
}
__ASSERT_DEBUG( iModel, Panic( EEikPanicListBoxNoModel ) );
if ( iModel->NumberOfItems() == 0 )
{
//DrawEmptyList();
}
else
{
TInt firstPotentialItemIndex = iTopItemIndex;
TInt lastPotentialItemIndex =
iTopItemIndex + NumberOfItemsThatFitInRect( iViewRect ) - 1;
TInt i;
ITEM_EXISTS_BEGIN;
for ( i = firstPotentialItemIndex; i <= lastPotentialItemIndex; i++ )
{
if ( ITEM_EXISTS( i ) )
{
DrawItem( i );
}
else
{
break;
}
}
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iGc );
if ( transApi )
{
transApi->StartDrawing( MAknListBoxTfxInternal::EListView );
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
TBool backgroundDrawn( EFalse );
TRect usedPortionOfViewRect(
iViewRect.iTl,
TSize( iViewRect.Width(),
( i - firstPotentialItemIndex ) * iItemHeight ) );
if ( iExtension && iExtension->iListBox )
{
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
MAknsControlContext* cc =
AknsDrawUtils::ControlContext( iExtension->iListBox );
if ( cc )
{
backgroundDrawn =
AknsDrawUtils::BackgroundBetweenRects( skin,
cc,
iExtension->iListBox,
*iItemDrawer->Gc(),
iViewRect,
usedPortionOfViewRect );
}
}
if ( !backgroundDrawn )
{
iItemDrawer->Gc()->SetBrushColor( iBackColor );
DrawUtils::ClearBetweenRects( *iItemDrawer->Gc(),
iViewRect,
usedPortionOfViewRect );
}
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
if ( transApi )
{
transApi->StopDrawing();
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::SetTopItemIndex(TInt aNewTopItemIndex)
{
_AKNTRACE_FUNC_ENTER;
TBool validIndex = (aNewTopItemIndex == 0) || (ITEM_EXISTS_ONCE(aNewTopItemIndex));
__ASSERT_ALWAYS(validIndex, Panic(EEikPanicListBoxInvalidTopItemIndexSpecified));
iTopItemIndex = aNewTopItemIndex;
CalcBottomItemIndex();
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CListBoxView::SetCurrentItemIndex(TInt aItemIndex)
{
_AKNTRACE_FUNC_ENTER;
TBool validIndex = (aItemIndex == 0) || (ITEM_EXISTS_ONCE(aItemIndex));
__ASSERT_ALWAYS(validIndex, Panic(EEikPanicListBoxInvalidCurrentItemIndexSpecified));
iCurrentItemIndex = aItemIndex;
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TInt CListBoxView::CurrentItemIndex() const
{
if (ITEM_EXISTS_ONCE(iCurrentItemIndex))
return iCurrentItemIndex;
else
return -1; // means there is no current item
}
EXPORT_C TBool CListBoxView::ScrollToMakeItemVisible(TInt aItemIndex)
{
_AKNTRACE_FUNC_ENTER;
TInt oldVerticalOffset = iVerticalOffset;
TInt newTopItemIndex = CalcNewTopItemIndexSoItemIsVisible( aItemIndex );
if ( ( ItemIsVisible( aItemIndex ) || aItemIndex < 0 )
&& iVerticalOffset == oldVerticalOffset
&& !(iFlags & EOffsetChanged) )
{
_AKNTRACE_FUNC_EXIT;
return EFalse;
}
if ( iVerticalOffset != oldVerticalOffset )
{
iFlags |= EOffsetChanged;
}
VScrollTo( newTopItemIndex );
iFlags &= ~EOffsetChanged;
_AKNTRACE_FUNC_EXIT;
return ETrue;
}
EXPORT_C TInt CListBoxView::CalcNewTopItemIndexSoItemIsVisible(TInt aItemIndex) const
{
_AKNTRACE_FUNC_ENTER;
#ifdef _DEBUG
RDebug::Print( _L( "CListBoxView::CalcNewTopItemIndexSoItemIsVisible" ) );
#endif // _DEBUG
TInt newTopItemIndex=iTopItemIndex;
const TInt numItemsThatFitInRect=NumberOfItemsThatFitInRect( iViewRect );
if ( aItemIndex < iTopItemIndex || numItemsThatFitInRect == 0 )
{
newTopItemIndex = aItemIndex;
}
else
{
if (aItemIndex > iBottomItemIndex)
{
newTopItemIndex = aItemIndex - numItemsThatFitInRect + 1;
}
}
if (!ITEM_EXISTS_ONCE(newTopItemIndex) && newTopItemIndex != 0 )
{ // if application fails to call HandleItemAdditionL(), we might go here.
// we dont want our OfferKeyEventL() to panic in that case.
newTopItemIndex = iTopItemIndex;
}
CListBoxView* me = const_cast<CListBoxView*>( this );
// change vertical offset value if needed
if ( aItemIndex <= iTopItemIndex && iVerticalOffset < 0 )
{
me->SetItemOffsetInPixels( 0 );
}
else if ( aItemIndex >= iBottomItemIndex && aItemIndex >= ( numItemsThatFitInRect - 1 ) )
{
TInt delta = iViewRect.Height() % iItemHeight;
if ( delta > 0 )
{
me->SetItemOffsetInPixels( -( iItemHeight - delta ) );
}
else
{
me->SetItemOffsetInPixels( 0 );
}
//after reset vertical offset,
//the number of items which fit in the view maybe change
TInt newNumItemsThatFitInRect = NumberOfItemsThatFitInRect( iViewRect );
if ( newNumItemsThatFitInRect != numItemsThatFitInRect )
{
newTopItemIndex = aItemIndex - newNumItemsThatFitInRect + 1;
}
}
_AKNTRACE_FUNC_EXIT;
return newTopItemIndex;
}
EXPORT_C void CListBoxView::DrawMatcherCursor()
{
// DrawMatcherCursor code is broken in S60, it will crash some lists. There
// is no need to draw matcher cursor in S60 -> deprecated method.
}
EXPORT_C void CListBoxView::HideMatcherCursor()
{
if (!(iFlags & EHasMatcherCursor))
return;
iGroupWin->CancelTextCursor();
}
EXPORT_C void CListBoxView::SetMatcherCursorPos(TInt aPosWithinCurrentItem)
{
iMatcherCursorPos = aPosWithinCurrentItem;
}
EXPORT_C TInt CListBoxView::MatcherCursorPos() const
{
return iMatcherCursorPos;
}
EXPORT_C void CListBoxView::SetMatcherCursorColor(TRgb aColor)
{
iMatcherCursorColor = aColor;
}
EXPORT_C void CListBoxView::SetMatcherCursor(TBool aMatcherCursor)
{
if (aMatcherCursor)
SetFlags(EHasMatcherCursor);
else
ClearFlags(EHasMatcherCursor);
}
EXPORT_C void CListBoxView::SetEmphasized(TBool aEmphasized)
{
if (aEmphasized)
SetFlags(EEmphasized);
else
ClearFlags(EEmphasized);
}
EXPORT_C void CListBoxView::SetDimmed(TBool aDimmed)
{
if (aDimmed)
SetFlags(EDimmed);
else
ClearFlags(EDimmed);
}
EXPORT_C void CListBoxView::SetDisableRedraw(TBool aDisableRedraw)
{
if (aDisableRedraw)
SetFlags(EDisableRedraw);
else
ClearFlags(EDisableRedraw);
}
EXPORT_C TBool CListBoxView::RedrawDisabled() const
{
return (iFlags & EDisableRedraw);
}
EXPORT_C void CListBoxView::SetPaintedSelection( TBool aPaintedSelection )
{
if ( aPaintedSelection )
SetFlags( EPaintedSelection );
else
ClearFlags( EPaintedSelection );
}
EXPORT_C TInt CListBoxView::DataWidth() const
{
return iDataWidth;
}
EXPORT_C TInt CListBoxView::VisibleWidth(const TRect& aRect) const
{
return aRect.Width();
}
EXPORT_C void CListBoxView::CalcDataWidth()
{
// The loop below causes HUGE performance problems for no reason
// with long lists.
#if NOT_NEEDED_IN_SERIES60
// assumes that iModel and iItemDrawer are both valid
// calculate data width (in pixels)
TInt largestItemWidth = 0;
TInt i = 0;
while (ITEM_EXISTS(i))
{
largestItemWidth = Max(largestItemWidth, iItemDrawer->ItemWidthInPixels(i));
++ i;
}
iDataWidth = largestItemWidth;
iDataWidth += LafListBox::InnerGutter();
iItemDrawer->SetItemCellSize(ItemSize());
#endif
}
EXPORT_C TRgb CListBoxView::BackColor() const
{
return iBackColor;
}
EXPORT_C void CListBoxView::SetBackColor(TRgb aColor)
{
iBackColor = aColor;
}
EXPORT_C TRgb CListBoxView::TextColor() const
{
return iTextColor;
}
EXPORT_C void CListBoxView::SetTextColor(TRgb aColor)
{
iTextColor = aColor;
}
EXPORT_C void CListBoxView::DrawEmptyList(const TRect & /*aClientRect*/) const
{
}
void CListBoxView::DisableVerticalLineDrawing( TBool aDisable )
{
iDisableVerticalLineDrawing = aDisable;
}
EXPORT_C void CListBoxView::SetItemOffsetInPixels(TInt aOffset)
{
if ( iExtension && !iExtension->iScrollingDisabled )
{
iVerticalOffset = aOffset;
}
else
{
// Make sure that offset is 0 when
// panning is disabled
iVerticalOffset = 0;
}
#ifdef _DEBUG
RDebug::Print( _L( "CListBoxView::SetItemOffsetInPixels, iVerticalOffset = %d" ), iVerticalOffset );
#endif // _DEBUG
}
EXPORT_C TInt CListBoxView::ItemOffsetInPixels() const
{
return iVerticalOffset;
}
void CListBoxView::SetScrolling( TBool aIsScrolling )
{
if ( iExtension )
{
iExtension->iScrolling = aIsScrolling;
}
}
void CListBoxView::SetItemIndex( TInt aItemIndex )
{
iCurrentItemIndex = aItemIndex;
}
// ---------------------------------------------------------------------------
// Returns ETrue if item is partially visible.
// ---------------------------------------------------------------------------
//
EXPORT_C TBool CListBoxView::ItemIsPartiallyVisible( TInt aItemIndex ) const
{
_AKNTRACE_FUNC_ENTER;
TPoint itemPosition( ItemPos( aItemIndex ) );
TBool itemPartiallyVisible =
( itemPosition.iY < iViewRect.iTl.iY &&
itemPosition.iY + iItemHeight >= iViewRect.iTl.iY ) ||
( itemPosition.iY <= iViewRect.iBr.iY &&
itemPosition.iY + iItemHeight > iViewRect.iBr.iY );
_AKNTRACE( "itemPartiallyVisible is %d", itemPartiallyVisible );
_AKNTRACE_FUNC_EXIT;
return itemPartiallyVisible;
}
// ---------------------------------------------------------------------------
// Resets the selection state so that there is nothing selected.
// ---------------------------------------------------------------------------
//
void CListBoxView::ClearSelection( TBool aDrawItems )
{
_AKNTRACE_FUNC_ENTER;
__ASSERT_DEBUG( iSelectionIndexes,
Panic( EEikPanicListBoxNoSelIndexArray ) );
TInt numSelectedItems = iSelectionIndexes->Count();
TKeyArrayFix key( 0, ECmpTInt );
TInt selectedItemIndex;
TInt pos;
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( iGc );
#endif // RD_UI_TRANSITION_EFFECTS_LIST
for ( TInt i = 0; i < numSelectedItems; i++ )
{
selectedItemIndex = ( *( iSelectionIndexes ) )[0];
if ( !( iSelectionIndexes->Find( selectedItemIndex, key, pos ) ) )
{
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
if ( transApi )
{
transApi->Invalidate( MAknListBoxTfxInternal::EListItem,
selectedItemIndex );
}
#endif // RD_UI_TRANSITION_EFFECTS_LIST
iSelectionIndexes->Delete( pos );
if ( aDrawItems )
{
DrawItem( selectedItemIndex );
}
}
}
ClearSelectionAnchorAndActiveIndex();
_AKNTRACE_FUNC_EXIT;
}
// class CSnakingListBoxView
EXPORT_C CSnakingListBoxView::CSnakingListBoxView()
{
iColumnWidth = 100;
}
EXPORT_C CSnakingListBoxView::~CSnakingListBoxView()
{
}
EXPORT_C void CSnakingListBoxView::CalcBottomItemIndex()
{
_AKNTRACE_FUNC_ENTER;
TInt i = iTopItemIndex;
iBottomItemIndex = i;
if ((iColumnWidth == 0) || (iItemHeight == 0))
{
_AKNTRACE_FUNC_EXIT;
return;
}
TInt xpos = iViewRect.iTl.iX;
TInt ypos = iViewRect.iTl.iY;
TInt maxXPos = xpos + (iViewRect.Width() / iColumnWidth) * iColumnWidth;
TInt maxYPos = ypos + ((iViewRect.Height() / iItemHeight) * iItemHeight)- iItemHeight;
ITEM_EXISTS_BEGIN;
while ((xpos < maxXPos) && (ITEM_EXISTS(i+1)))
{
++ i;
if (ypos == maxYPos)
{
ypos = iViewRect.iTl.iY;
xpos += iColumnWidth;
}
else
ypos += iItemHeight;
}
if ((i > 0) && (xpos >= maxXPos))
--i;
iBottomItemIndex = i;
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CSnakingListBoxView::CalcRowAndColIndexesFromItemIndex(TInt aItemIndex, TInt& aRowIndex, TInt& aColIndex) const
{
// should panic if iItemHeight or iViewRect.Height() is 0
// assumes specified item is currently visible
_AKNTRACE_FUNC_ENTER;
TInt numOfItemsFromFirstVisibleItem = (aItemIndex - iTopItemIndex);
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
aColIndex = numOfItemsFromFirstVisibleItem / numOfItemsPerColumn;
aRowIndex = numOfItemsFromFirstVisibleItem % numOfItemsPerColumn;
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TInt CSnakingListBoxView::NumberOfItemsPerColumn() const
{
TInt numOfItemsPerColumn = iViewRect.Height() / iItemHeight;
return (numOfItemsPerColumn<1? 1: numOfItemsPerColumn);
}
EXPORT_C void CSnakingListBoxView::CalcItemIndexFromRowAndColIndexes(TInt& aItemIndex, TInt aRowIndex, TInt aColIndex) const
{
_AKNTRACE_FUNC_ENTER;
__ASSERT_DEBUG((aRowIndex >= 0), Panic(EEikPanicListBoxInvalidRowIndexSpecified));
__ASSERT_DEBUG((aColIndex >= 0), Panic(EEikPanicListBoxInvalidColIndexSpecified));
// should panic if iItemHeight is 0
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
aItemIndex = iTopItemIndex + ((aColIndex * numOfItemsPerColumn) + aRowIndex);
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TPoint CSnakingListBoxView::ItemPos(TInt aItemIndex) const
{
TInt rowIndex, colIndex;
CalcRowAndColIndexesFromItemIndex(aItemIndex, rowIndex, colIndex);
return TPoint(iViewRect.iTl.iX + colIndex * iColumnWidth, iViewRect.iTl.iY + rowIndex * iItemHeight);
}
EXPORT_C TBool CSnakingListBoxView::XYPosToItemIndex(TPoint aPosition, TInt& aItemIndex) const
{
// returns ETrue and sets aItemIndex to the index of the item whose bounding box contains aPosition
// returns EFalse if no such item exists
_AKNTRACE_FUNC_ENTER;
TBool itemFound = EFalse;
if ((iColumnWidth == 0) || (iItemHeight == 0))
{
_AKNTRACE_FUNC_EXIT;
return EFalse;
}
if (iViewRect.Contains(aPosition))
{
// aPosition is inside the display area
TInt yOffsetFromViewRectOrigin = aPosition.iY - iViewRect.iTl.iY;
TInt xOffsetFromViewRectOrigin = aPosition.iX - iViewRect.iTl.iX;
TInt colIndex = xOffsetFromViewRectOrigin / iColumnWidth;
TInt rowIndex = yOffsetFromViewRectOrigin / iItemHeight;
// now work out the item index given that we know which row and column it is in
TInt itemIndex;
CalcItemIndexFromRowAndColIndexes(itemIndex, rowIndex, colIndex);
if ((ITEM_EXISTS_ONCE(itemIndex)) && (ItemIsVisible(itemIndex)))
{
aItemIndex = itemIndex;
itemFound = ETrue;
}
}
_AKNTRACE_FUNC_EXIT;
return itemFound;
}
EXPORT_C void CSnakingListBoxView::MoveCursorL(TCursorMovement aCursorMovement, TSelectionMode aSelectionMode)
{
if (aCursorMovement == ECursorNextColumn)
MoveToNextColumnL(aSelectionMode);
else if (aCursorMovement == ECursorPreviousColumn)
MoveToPreviousColumnL(aSelectionMode);
else
CListBoxView::MoveCursorL(aCursorMovement, aSelectionMode);
}
EXPORT_C TSize CSnakingListBoxView::ItemSize(TInt /*aItemIndex*/) const
{
return TSize(iColumnWidth, iItemHeight);
}
EXPORT_C void CSnakingListBoxView::SetColumnWidth(TInt aColumnWidth)
{
TBool validColumnWidth = (aColumnWidth > 0);
__ASSERT_ALWAYS(validColumnWidth, Panic(EEikPanicListBoxInvalidColumnWidthSpecified));
iColumnWidth = aColumnWidth;
CalcBottomItemIndex();
iItemDrawer->SetItemCellSize(ItemSize());
}
EXPORT_C TInt CSnakingListBoxView::NumberOfItemsThatFitInRect(const TRect& aRect) const
{
_AKNTRACE_FUNC_ENTER;
if ((iItemHeight == 0) || (iColumnWidth == 0))
{
_AKNTRACE_FUNC_EXIT;
return 0;
}
TInt numOfRows = aRect.Height() / iItemHeight;
TInt numOfCols = aRect.Width() / iColumnWidth;
_AKNTRACE_FUNC_EXIT;
return (numOfRows * numOfCols);
}
EXPORT_C void CSnakingListBoxView::ClearUnusedItemSpace(TInt aStartItemIndex, TInt aEndItemIndex) const
{
TRect blankRect;
for (TInt i = aStartItemIndex; i <= aEndItemIndex; i++)
{
blankRect.SetRect(ItemPos(i), ItemSize());
iItemDrawer->ClearRect(blankRect);
}
}
EXPORT_C void CSnakingListBoxView::MoveToPreviousColumnL(TSelectionMode aSelectionMode)
{
_AKNTRACE_FUNC_ENTER;
TInt oldCurrentItemIndex = iCurrentItemIndex;
TInt indexOfNewCurrentItem = iCurrentItemIndex;
// TInt indexOfNewTopItem = iTopItemIndex;
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
indexOfNewCurrentItem = iCurrentItemIndex - numOfItemsPerColumn;
if (indexOfNewCurrentItem < 0)
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (ITEM_EXISTS_ONCE(indexOfNewCurrentItem))
{
iCurrentItemIndex = indexOfNewCurrentItem;
if (!(ItemIsSelected(oldCurrentItemIndex)) || (aSelectionMode != ESingleSelection))
DrawItem(oldCurrentItemIndex);
if (iCurrentItemIndex < iTopItemIndex)
{
UpdateSelectionL(aSelectionMode);
ScrollToMakeItemVisible(iCurrentItemIndex);
}
else
{
ScrollToMakeItemVisible(iCurrentItemIndex);
UpdateSelectionL(aSelectionMode);
}
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CSnakingListBoxView::MoveToNextColumnL(TSelectionMode aSelectionMode)
{
_AKNTRACE_FUNC_ENTER;
TInt oldCurrentItemIndex = iCurrentItemIndex;
TInt indexOfNewCurrentItem = iCurrentItemIndex;
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
indexOfNewCurrentItem = iCurrentItemIndex + numOfItemsPerColumn;
ITEM_EXISTS_BEGIN;
if (ITEM_EXISTS(indexOfNewCurrentItem) == EFalse)
{
TInt indexOfItemAtTopOfTargetCol = (indexOfNewCurrentItem / numOfItemsPerColumn) * numOfItemsPerColumn;
if (! (ITEM_EXISTS(indexOfItemAtTopOfTargetCol)))
{
_AKNTRACE_FUNC_EXIT;
return; // no more columns of data to the right, so just return
}
// there are more columns of data available to the right of the current column
// since there is no item at the expected position, look for an item further up in the same column
TInt i = indexOfNewCurrentItem;
while (ITEM_EXISTS(i) == EFalse)
--i;
indexOfNewCurrentItem = i;
}
iCurrentItemIndex = indexOfNewCurrentItem;
if (!(ItemIsSelected(oldCurrentItemIndex)) || (aSelectionMode != ESingleSelection))
DrawItem(oldCurrentItemIndex);
if (iCurrentItemIndex > iBottomItemIndex)
{
UpdateSelectionL(aSelectionMode);
ScrollToMakeItemVisible(iCurrentItemIndex);
}
else
{
ScrollToMakeItemVisible(iCurrentItemIndex);
UpdateSelectionL(aSelectionMode);
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C TInt CSnakingListBoxView::CalcNewTopItemIndexSoItemIsVisible(TInt aItemIndex) const
{
_AKNTRACE_FUNC_ENTER;
if (aItemIndex == iTopItemIndex)
{
_AKNTRACE_FUNC_EXIT;
return iTopItemIndex;
}
TInt newTopItemIndex = iTopItemIndex;
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
TInt colIndexOfTargetItem = aItemIndex / numOfItemsPerColumn;
TInt numOfColsThatFitInViewRect = VisibleWidth(iViewRect);
if (aItemIndex < iTopItemIndex)
newTopItemIndex = colIndexOfTargetItem * numOfItemsPerColumn;
else if (aItemIndex > iBottomItemIndex)
{
TInt colIndexOfNewBottomItem = colIndexOfTargetItem;
TInt colIndexOfNewTopItem = colIndexOfNewBottomItem - (numOfColsThatFitInViewRect - 1);
newTopItemIndex = colIndexOfNewTopItem * numOfItemsPerColumn;
}
_AKNTRACE_FUNC_EXIT;
return newTopItemIndex;
}
EXPORT_C void CSnakingListBoxView::HScroll(TInt aHScrollAmount)
{
// note: aHScrollAmount is assumed to be specified in terms of number of columns;
// a negative value ==> we need to scroll view contents to the right
_AKNTRACE_FUNC_ENTER;
if ((aHScrollAmount == 0) || (iItemHeight == 0))
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (RedrawDisabled())
{
_AKNTRACE_FUNC_EXIT;
return;
}
iHScrollOffset += aHScrollAmount;
TInt numOfColsThatFitInViewRect = VisibleWidth(iViewRect);
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
if (Abs(aHScrollAmount) >= numOfColsThatFitInViewRect)
{
iTopItemIndex = iTopItemIndex + (numOfItemsPerColumn * aHScrollAmount);
CalcBottomItemIndex();
Draw();
}
else
{
TInt oldTopItemIndex = iTopItemIndex;
TInt usedViewRectPortionWidth = VisibleWidth(iViewRect) * iColumnWidth;
TInt usedViewRectPortionHeight = (iViewRect.Height() / iItemHeight) * iItemHeight;
TRect usedPortionOfViewRect(iViewRect.iTl, TSize(usedViewRectPortionWidth, usedViewRectPortionHeight));
iWin->Scroll(usedPortionOfViewRect, TPoint(-aHScrollAmount * iColumnWidth, 0));
// iWin->Scroll(iViewRect, TPoint(-aHScrollAmount * iColumnWidth, 0));
iTopItemIndex = iTopItemIndex + (numOfItemsPerColumn * aHScrollAmount);
CalcBottomItemIndex();
TInt colIndexOfOldTopItem = oldTopItemIndex / numOfItemsPerColumn;
TRect redrawRect;
TInt startColIndex;
TInt endColIndex;
if (aHScrollAmount > 0)
{
redrawRect.SetRect(TPoint((numOfColsThatFitInViewRect - aHScrollAmount) * iColumnWidth + iViewRect.iTl.iX, iViewRect.iTl.iY), iViewRect.iBr);
startColIndex = colIndexOfOldTopItem + numOfColsThatFitInViewRect;
endColIndex = startColIndex + aHScrollAmount - 1;
}
else
{
redrawRect.SetRect(iViewRect.iTl, TPoint(Abs(aHScrollAmount) * iColumnWidth + iViewRect.iTl.iX, iViewRect.iBr.iY));
startColIndex = colIndexOfOldTopItem + aHScrollAmount;
endColIndex = colIndexOfOldTopItem - 1;
}
redrawRect.Intersection(iViewRect);
iWin->Invalidate(iViewRect);
iWin->BeginRedraw(iViewRect);
DrawColumnRange(startColIndex, endColIndex);
iWin->EndRedraw();
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CSnakingListBoxView::CalcDataWidth()
{
// assumes that iModel and iItemDrawer are both valid
// assumes that the model knows how many items there are...
// calculate data width (in columns)
iDataWidth = 0;
if ((iViewRect.Height() == 0) || (iItemHeight == 0))
return;
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
iDataWidth = iModel->NumberOfItems() / numOfItemsPerColumn;
if (iModel->NumberOfItems() % numOfItemsPerColumn)
iDataWidth++; // add on one column if remainder != 0
}
EXPORT_C TInt CSnakingListBoxView::VisibleWidth(const TRect& aRect) const
{
return aRect.Width() / iColumnWidth;
}
EXPORT_C void CSnakingListBoxView::Draw(const TRect* aClipRect) const
{
// temporary: some code sharing with CListBoxView::Draw() is needed!
_AKNTRACE_FUNC_ENTER;
if (RedrawDisabled())
{
_AKNTRACE_FUNC_EXIT;
return;
}
__ASSERT_DEBUG(iModel, Panic(EEikPanicListBoxNoModel));
if (iItemHeight == 0)
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (! aClipRect)
aClipRect = &iViewRect;
iItemDrawer->ClearRect(iViewRect);
if (iModel->NumberOfItems() == 0)
{
// call to this was moved to CEikListBox::Draw(), because we need the whole clientrect
// to do the drawing correctly.
//DrawEmptyList();
}
else
{
TInt firstPotentialItemIndex = iTopItemIndex;
TInt lastPotentialItemIndex = iTopItemIndex + NumberOfItemsThatFitInRect(iViewRect) - 1;
TInt i;
ITEM_EXISTS_BEGIN;
for (i = firstPotentialItemIndex; i <= lastPotentialItemIndex; i++)
if (ITEM_EXISTS(i))
DrawItem(i);
else
{
ClearUnusedItemSpace(i, lastPotentialItemIndex);
break;
}
// clear the unused portion of the viewing area
TInt usedViewRectPortionWidth = VisibleWidth(iViewRect) * iColumnWidth;
TInt usedViewRectPortionHeight = (iViewRect.Height() / iItemHeight) * iItemHeight;
TRect usedPortionOfViewRect(iViewRect.iTl, TSize(usedViewRectPortionWidth, usedViewRectPortionHeight));
iItemDrawer->Gc()->SetBrushColor( BackColor() );
DrawUtils::ClearBetweenRects( *iItemDrawer->Gc(), iViewRect, usedPortionOfViewRect );
// ((CSnakingListBoxView*)this)->iBottomItemIndex = i - 1;
}
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CSnakingListBoxView::DrawItemRange(TInt aStartItemIndex, TInt aEndItemIndex) const
{
// temporary: some code sharing with CSnakingListBoxView::Draw() is needed!
_AKNTRACE_FUNC_ENTER;
if (RedrawDisabled())
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (iItemHeight == 0)
{
_AKNTRACE_FUNC_EXIT;
return;
}
TInt i;
ITEM_EXISTS_BEGIN;
for (i = aStartItemIndex; i <= aEndItemIndex; i++)
if (ITEM_EXISTS(i))
DrawItem(i);
else
{
ClearUnusedItemSpace(i, aEndItemIndex);
break;
}
TInt usedViewRectPortionWidth = VisibleWidth(iViewRect) * iColumnWidth;
TInt usedViewRectPortionHeight = (iViewRect.Height() / iItemHeight) * iItemHeight;
TRect usedPortionOfViewRect(iViewRect.iTl, TSize(usedViewRectPortionWidth, usedViewRectPortionHeight));
iItemDrawer->Gc()->SetBrushColor( BackColor() );
DrawUtils::ClearBetweenRects( *iItemDrawer->Gc(), iViewRect, usedPortionOfViewRect);
_AKNTRACE_FUNC_EXIT;
}
EXPORT_C void CSnakingListBoxView::DrawColumnRange(TInt aStartColIndex, TInt aEndColIndex) const
{
_AKNTRACE_FUNC_ENTER;
if (RedrawDisabled())
{
_AKNTRACE_FUNC_EXIT;
return;
}
if (iItemHeight == 0)
{
_AKNTRACE_FUNC_EXIT;
return;
}
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
TInt startItemIndex = aStartColIndex * numOfItemsPerColumn;
TInt endItemIndex = aEndColIndex * numOfItemsPerColumn + numOfItemsPerColumn - 1;
DrawItemRange(startItemIndex, endItemIndex);
}
EXPORT_C void CSnakingListBoxView::SetTopItemIndex(TInt aNewTopItemIndex)
{
if (iViewRect.Height() == 0)
return;
CListBoxView::SetTopItemIndex(aNewTopItemIndex);
UpdateHScrollOffsetBasedOnTopItemIndex();
}
EXPORT_C void CSnakingListBoxView::SetItemHeight(TInt aItemHeight)
{
CListBoxView::SetItemHeight(aItemHeight);
CalcBottomItemIndex();
UpdateHScrollOffsetBasedOnTopItemIndex();
}
EXPORT_C void CSnakingListBoxView::UpdateHScrollOffsetBasedOnTopItemIndex()
{
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
iHScrollOffset = iTopItemIndex / numOfItemsPerColumn;
}
EXPORT_C TBool CSnakingListBoxView::ScrollToMakeItemVisible(TInt aItemIndex)
{
_AKNTRACE_FUNC_ENTER;
if ((RedrawDisabled()) || (ItemIsVisible(aItemIndex)) || (iViewRect.Height() == 0))
{
_AKNTRACE_FUNC_EXIT;
return EFalse;
}
HideMatcherCursor();
TInt amountToScroll = CalculateHScrollOffsetSoItemIsVisible(aItemIndex);
HScroll(amountToScroll);
DrawMatcherCursor();
_AKNTRACE_FUNC_EXIT;
return ETrue;
}
EXPORT_C TInt CSnakingListBoxView::CalculateHScrollOffsetSoItemIsVisible(TInt aItemIndex)
{
// returns the number of cols that we need to scroll, 0 if no scrolling is needed
_AKNTRACE_FUNC_ENTER;
TInt newTopItemIndex = CalcNewTopItemIndexSoItemIsVisible(aItemIndex);
TInt numOfItemsPerColumn = NumberOfItemsPerColumn();
TInt oldHScrollOffset = iHScrollOffset;
TInt newHScrollOffset = newTopItemIndex / numOfItemsPerColumn;
TInt numOfColsToScroll = newHScrollOffset - oldHScrollOffset;
_AKNTRACE_FUNC_EXIT;
return numOfColsToScroll;
}
EXPORT_C TAny* CSnakingListBoxView::Reserved_1()
{
return NULL;
}