// EIKLBX.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//
  
#include <e32base.h>
#include <e32keys.h>
#include <bamatch.h>
#include <badesca.h>
#include <barsread.h>
#include <eiklbx.h>
#include <eiklbv.h>
#include <eiklbi.h>
#include <eiklbm.h>
#include <eikenv.h>
#include <eiklbx.pan>
#include <eikbordr.h>
#include <eikbutb.h>
#include <coemain.h>
#include <w32std.h>
#include <eikdutil.h>
#include <eiklbx.hrh>
#include <eikkeys.h>

//
// class CEikMatchBuffer
//

class CMatchBuffer : public CBase
	{	
public:
	enum TExtent
		{ EFull, EMinimal };
public:
	static CMatchBuffer* NewL(TExtent aExtent);
	~CMatchBuffer();
	void ConstructMatchBufferL();
public:
	RIncrMatcherBase* iMatchBuffer;
	TInt iPressedIndex;	
	};

CMatchBuffer* CMatchBuffer::NewL(TExtent aExtent)
	{
	CMatchBuffer* buffer=new(ELeave) CMatchBuffer;
	if (aExtent==EFull)
		{
		CleanupStack::PushL(buffer);
		buffer->iMatchBuffer=new(ELeave)RIncrMatcherBuf<CEikListBox::KEikMaxMatchingBufferLength>;
		CleanupStack::Pop(); // buffer
		}
	return buffer;
	}

CMatchBuffer::~CMatchBuffer()
	{
	delete iMatchBuffer;
	}

void CMatchBuffer::ConstructMatchBufferL()
	{
	iMatchBuffer=new(ELeave)RIncrMatcherBuf<CEikListBox::KEikMaxMatchingBufferLength>;
	}

//
// class CListBoxExt
//

class CListBoxExt : public CBase, public MListVisibilityObserver
	{
public:
	static CListBoxExt* NewL(CEikListBox& aListBox);
	
	~CListBoxExt();
	CListBoxExt(CEikListBox& aListBox);

	// new functions
	void CreateMatchBufferL();
	void CheckCreateBufferL();
	CMatchBuffer* Buffer() const;
	TBool IsMatchBuffer() const;
public: // from MListVisibilityObserver
	TBool IsVisible() const;
private:
	CMatchBuffer* iBuffer;
	CEikListBox& iListBox;
	};

CListBoxExt* CListBoxExt::NewL(CEikListBox& aListBox)
	{ // static
	CListBoxExt* self=new(ELeave)CListBoxExt(aListBox);
	return self;
	}

CListBoxExt::CListBoxExt(CEikListBox& aListBox)
	: iListBox(aListBox)
	{
	}

CListBoxExt::~CListBoxExt()
	{
	delete iBuffer;
	}

void CListBoxExt::CheckCreateBufferL()
	{
	if (!iBuffer)
		iBuffer=CMatchBuffer::NewL(CMatchBuffer::EMinimal);
	}

CMatchBuffer* CListBoxExt::Buffer() const
	{
	return iBuffer;
	}

void CListBoxExt::CreateMatchBufferL()
	{
	if (iBuffer==NULL)
		iBuffer=CMatchBuffer::NewL(CMatchBuffer::EFull);
	else if (iBuffer->iMatchBuffer==NULL)
		iBuffer->ConstructMatchBufferL();
	}

TBool CListBoxExt::IsVisible() const
	{
	return iListBox.IsVisible();
	}

TBool CListBoxExt::IsMatchBuffer() const
	{
	return (iBuffer && iBuffer->iMatchBuffer);
	}

//
// class CEikListBox
//

const TInt KEikListBoxHNudgeSizeAsFractionOfViewRectWidth = 20;	
const TInt KEikListBoxBackgroundColor = 15;		// later, this will be a data member of the listbox  
const TInt KEikListBoxItemVGap = 6;	// to allow a box to be drawn around each item

const TInt KEikListBoxPointerRepeatInterval = 100;  // in micro conds
const TInt KEikListBoxInvalidIndex=-1;

GLDEF_C void Panic(TEikListBoxPanic aPanic)
    {
    User::Panic(_L("EIKON-LISTBOX"),aPanic);
    }

EXPORT_C CEikListBox::CEikListBox()
	: iHorizontalMargin(2),
	iVerticalMargin(2)
	{
    iBorder=TEikBorder(TEikBorder::ESingleGray);
	iItemHeight = iEikonEnv->NormalFont()->HeightInPixels() + KEikListBoxItemVGap;
//	iBackColor = KDefaultLbxBackColor;
	iBackColor = CEikonEnv::Static()->Color(EEikColorControlBackground); //KDefaultLbxBackColor
	SetComponentsToInheritVisibility(ETrue);
	}

EXPORT_C CEikListBox::~CEikListBox()
    {
	delete(iListBoxExt);
	delete(iSBFrame);
    if (!(iListBoxFlags & EKeepModel))
    	delete iModel;
	if (iView)
		delete iView;
	else
		delete iItemDrawer;
	if (iLaunchingButton)
		{
		TPointerEvent event;
		event.iType=TPointerEvent::EButton1Up;
		event.iModifiers=0;
		event.iPosition=iLaunchingButton->Position();
		iLaunchingButton->HandlePointerEventL(event); // won't leave
		}
    }

EXPORT_C TBool CEikListBox::ItemExists(TInt aItemIndex) const
	{
	return ((aItemIndex >= 0) && (aItemIndex < iModel->NumberOfItems()));
	}

EXPORT_C void CEikListBox::RestoreCommonListBoxPropertiesL(TResourceReader& aReader)
    {
    iListBoxFlags = aReader.ReadInt16();
	iRequiredHeightInNumOfItems = aReader.ReadInt16();

	if (iListBoxFlags & EIncrementalMatching)
		CreateMatchBufferL();
    }

EXPORT_C MListBoxModel* CEikListBox::Model() const
	{
	return iModel;
	}

EXPORT_C CListBoxView* CEikListBox::View() const
	{
	return iView;
	}

EXPORT_C void CEikListBox::CreateMatchBufferL()
	{
	CheckCreateExtensionL();
	iListBoxExt->CreateMatchBufferL();
	}

EXPORT_C void CEikListBox::SetItemHeightL(TInt aHeight)
	{
	// won't actually leave if the horizontal/vertical scrollbars have both been turned off
	__ASSERT_ALWAYS((aHeight > 0), Panic(EEikPanicListBoxInvalidItemHeightSpecified));
	iItemHeight = aHeight;
	TRect clientRect = iBorder.InnerRect(Rect());
	SetViewRectFromClientRect(clientRect);
	if (iView)
		iView->SetItemHeight(aHeight);
	HandleViewRectSizeChangeL();
	}

EXPORT_C TInt CEikListBox::ItemHeight() const
	{
	return iItemHeight;
	}

EXPORT_C TInt CEikListBox::CalcWidthBasedOnNumOfChars(TInt aNumOfChars) const
	{
	return CalcWidthBasedOnRequiredItemWidth(aNumOfChars * iEikonEnv->NormalFont()->MaxNormalCharWidthInPixels());
	}

EXPORT_C TInt CEikListBox::CalcWidthBasedOnRequiredItemWidth(TInt aTextWidthInPixels) const
	{
	TInt width = aTextWidthInPixels;
	width += (2 * iHorizontalMargin);
	width += iBorder.SizeDelta().iWidth;
	if (iSBFrame)
		{
		if (iSBFrame->VScrollBarVisibility()!=CEikScrollBarFrame::EOff)
			width += CEikScrollBar::EScrollbarWidth;
		}
	return width;
	}

EXPORT_C TInt CEikListBox::CalcHeightBasedOnNumOfItems(TInt aNumOfItems) const
	{
	TInt height;
	height = (aNumOfItems * iItemHeight);
	height += (2 * iVerticalMargin);
	height += iBorder.SizeDelta().iHeight;
	if (iSBFrame)
		{
		if (iSBFrame->HScrollBarVisibility()!=CEikScrollBarFrame::EOff)
			height += CEikScrollBar::EScrollbarWidth;
		}
	return height;
	}

EXPORT_C TSize CEikListBox::MinimumSize()
    {
	TSize size;
	TSize minCellSize(iItemDrawer->MinimumCellSize());
	size.iWidth = minCellSize.iWidth + (iHorizontalMargin * 2);
	size.iHeight = (iVerticalMargin * 2) + (iRequiredHeightInNumOfItems * minCellSize.iHeight);
	if ((!(iListBoxFlags & EScrollBarSizeExcluded)) && iSBFrame)
		{
		if (iSBFrame->VScrollBarVisibility()!=CEikScrollBarFrame::EOff)
			size.iWidth += CEikScrollBar::EScrollbarWidth;
		if (iSBFrame->HScrollBarVisibility()!=CEikScrollBarFrame::EOff)
			size.iHeight += CEikScrollBar::EScrollbarWidth;
		}
	size += iBorder.SizeDelta();
	return size;
    }

EXPORT_C TSize CEikListBox::CalcSizeInPixels(TInt aWidthAsNumOfChars, TInt aHeightAsNumOfItems) const
	{
	return TSize(CalcWidthBasedOnNumOfChars(aWidthAsNumOfChars), CalcHeightBasedOnNumOfItems(aHeightAsNumOfItems));
	}

EXPORT_C CEikScrollBarFrame* CEikListBox::CreateScrollBarFrameL(TBool aPreAlloc)
	{
	if (!iSBFrame)
		iSBFrame=new(ELeave) CEikScrollBarFrame(this, this, aPreAlloc); 
	return iSBFrame;
	}

EXPORT_C void CEikListBox::HandleViewRectSizeChangeL()
	{
	iView->CalcBottomItemIndex();
	iView->CalcDataWidth();
	TInt currentItemIndex = iView->CurrentItemIndex();
	if ((ItemExists(currentItemIndex)) && (!(iView->ItemIsVisible(currentItemIndex))))
		{
		TInt newTopItemIndex = iView->CalcNewTopItemIndexSoItemIsVisible(currentItemIndex);
		iView->SetTopItemIndex(newTopItemIndex);
		}
	UpdateScrollBarsL();
	}

EXPORT_C void CEikListBox::SizeChangedL()
    {
	TRect clientRect = iBorder.InnerRect(Rect());
	SetViewRectFromClientRect(clientRect);
	HandleViewRectSizeChangeL();
	}

EXPORT_C TInt CEikListBox::CountComponentControls() const
	{
	TInt count=CEikBorderedControl::CountComponentControls();
	if (iSBFrame)
		count+=iSBFrame->CountComponentControls();
	return count;
	}

EXPORT_C CCoeControl* CEikListBox::ComponentControl(TInt aIndex) const
	{
	TInt baseCount=CEikBorderedControl::CountComponentControls();
	if (aIndex<baseCount)
		return CEikBorderedControl::ComponentControl(aIndex);
	aIndex-=baseCount;
	return iSBFrame->ComponentControl(aIndex);
	}

EXPORT_C void CEikListBox::SetViewRectFromClientRect(const TRect& aClientRect)
	{
	TRect rect(aClientRect);
	rect.Shrink(iHorizontalMargin, iVerticalMargin);
	iViewRectHeightAdjustment = AdjustRectHeightToWholeNumberOfItems(rect);
	iView->SetViewRect(rect);
	}

EXPORT_C void CEikListBox::RestoreClientRectFromViewRect(TRect& aClientRect) const
	{
	aClientRect=iView->ViewRect();
	aClientRect.Grow(iHorizontalMargin, iVerticalMargin);
	// height may have been rounded so correct it
	if (!iViewRectHeightAdjustment)
		return;
	if (iViewRectHeightAdjustment % 2 !=0)
		aClientRect.iBr.iY += 1;
	aClientRect.Grow(0, iViewRectHeightAdjustment/2);
	// aClientRect.iBr.iY += iViewRectHeightAdjustment;
	}

EXPORT_C TInt CEikListBox::AdjustRectHeightToWholeNumberOfItems(TRect& aRect) const
	{
	// round down the height of aRect (if necessary) so that only a whole number of items can be displayed inside the listbox
	// returns the number of pixels reduced.
	TInt remainder = aRect.Height() % iItemHeight;
	if (remainder != 0) 
		{
		// need to adjust viewRect 
		aRect.Shrink(0, remainder/2);
		if (remainder % 2 != 0)		
			aRect.iBr.iY -= 1;
		// aRect.iBr.iY -= remainder;
		}
	return remainder;
	}

EXPORT_C void CEikListBox::CalculatePopoutRect(TInt aTargetItemIndex, TInt aTargetYPos, TRect& aListBoxRect, TInt aMinHeightInNumOfItems) 
    {
	// this function is designed for use by the choice list control
	TInt listBoxHeight = 0;
	TInt listBoxYPos = 0;
	TInt screenHeight = iCoeEnv->ScreenDevice()->SizeInPixels().iHeight;
	TInt maxDisplayedItems = (screenHeight - (2 * iVerticalMargin) - iBorder.SizeDelta().iHeight) / iItemHeight;
	TInt desiredHeightInNumOfItems = Max(iModel->NumberOfItems(), aMinHeightInNumOfItems);
	if (desiredHeightInNumOfItems > maxDisplayedItems)
		{
		listBoxHeight = CalcHeightBasedOnNumOfItems(maxDisplayedItems); 	
		listBoxYPos = (screenHeight - listBoxHeight) / 2;
		TInt numOfDisplayedItemsAboveTarget = (aTargetYPos-listBoxYPos-iVerticalMargin)/iItemHeight;
		TInt topItemOrdinal=Max(0, (aTargetItemIndex-numOfDisplayedItemsAboveTarget));
		topItemOrdinal=Min(iModel->NumberOfItems()-maxDisplayedItems,topItemOrdinal);
		iView->SetTopItemIndex(iView->TopItemIndex()+topItemOrdinal);
		aListBoxRect.iTl.iY = listBoxYPos;
		aListBoxRect.iBr.iY = listBoxYPos + listBoxHeight;
		return;
		}
	listBoxHeight = CalcHeightBasedOnNumOfItems(desiredHeightInNumOfItems);
	TInt numOfItemsAbove = aTargetItemIndex;
	TInt potentialPixelsAboveTarget = 0;
	if (numOfItemsAbove > 0)
		potentialPixelsAboveTarget = numOfItemsAbove * iItemHeight + iVerticalMargin + iBorder.Margins().iTop;
	listBoxYPos = aTargetYPos - potentialPixelsAboveTarget;
	if ((listBoxYPos + listBoxHeight) >= screenHeight)
		listBoxYPos = screenHeight - listBoxHeight;
	if (potentialPixelsAboveTarget>aTargetYPos)
		listBoxYPos = 0;
	// find number of items below aTargetItemIndex
	TInt numberOfItemsBelowTarget = 0;
	TInt targetIndex = aTargetItemIndex;
	while (ItemExists(++targetIndex))
		++numberOfItemsBelowTarget;
	TInt potentialPixelsBelowTarget = 0;
	if (numberOfItemsBelowTarget > 0)
		potentialPixelsBelowTarget = numberOfItemsBelowTarget * iItemHeight + iVerticalMargin + iBorder.Margins().iBottom;
	if ((potentialPixelsBelowTarget + iItemHeight) > (screenHeight-aTargetYPos))
		listBoxYPos = screenHeight - listBoxHeight;
	aListBoxRect.iTl.iY = listBoxYPos;
	aListBoxRect.iBr.iY = listBoxYPos + listBoxHeight;
    }

EXPORT_C TInt CEikListBox::TopItemIndex() const
	{
	__ASSERT_DEBUG(iView, Panic(EEikPanicListBoxNoView));
	return iView->TopItemIndex();
	}

EXPORT_C TInt CEikListBox::BottomItemIndex() const
	{
	__ASSERT_DEBUG(iView, Panic(EEikPanicListBoxNoView));
	return iView->BottomItemIndex();
	}

EXPORT_C void CEikListBox::SetTopItemIndex(TInt aItemIndex) const
	{
	__ASSERT_DEBUG(iView, Panic(EEikPanicListBoxNoView));
	iView->SetTopItemIndex(aItemIndex);
	UpdateScrollBarThumbs();
	}

EXPORT_C void CEikListBox::AdjustTopItemIndex() const
	{
	TInt maxTopItemIndex=iView->BottomItemIndex() - iView->NumberOfItemsThatFitInRect(iView->ViewRect()) +1;
	maxTopItemIndex=Max(0, maxTopItemIndex);
	if (iView->TopItemIndex() > maxTopItemIndex)
		SetTopItemIndex(maxTopItemIndex);
	}

EXPORT_C TInt CEikListBox::CurrentItemIndex() const
	{
	__ASSERT_ALWAYS(iView, Panic(EEikPanicListBoxNoView));
	return iView->CurrentItemIndex();
	}

EXPORT_C void CEikListBox::UpdateCurrentItem(TInt aItemIndex) const
	{
	TInt oldCurrentItemIndex = iView->CurrentItemIndex();
	iView->SetCurrentItemIndex(aItemIndex);
	iView->DrawItem(oldCurrentItemIndex);
	if (!(iView->ItemIsVisible(aItemIndex)))
		{
		SetTopItemIndex(iView->CalcNewTopItemIndexSoItemIsVisible(aItemIndex));
		DrawNow();
		}
	if (!(iListBoxFlags & EMultipleSelection))
		{
		TRAPD(err,iView->UpdateSelectionL(CListBoxView::ESingleSelection));
		if (err!=KErrNone)
			iEikonEnv->NotifyIdleErrorWhileRedrawing(err);
		}
	DrawItem(aItemIndex);
	}

EXPORT_C void CEikListBox::SetCurrentItemIndex(TInt aItemIndex) const
	{
	__ASSERT_ALWAYS(iView, Panic(EEikPanicListBoxNoView));
	TBool redrawDisabled = iView->RedrawDisabled();
	iView->SetDisableRedraw(ETrue);
	UpdateCurrentItem(aItemIndex);
	iView->SetDisableRedraw(redrawDisabled);
	}

EXPORT_C void CEikListBox::SetCurrentItemIndexAndDraw(TInt aItemIndex) const
	{
	__ASSERT_ALWAYS(iView, Panic(EEikPanicListBoxNoView));
	UpdateCurrentItem(aItemIndex);
	}

EXPORT_C void CEikListBox::ConstructL(const CCoeControl* aParent,TInt aFlags)
	{
	iListBoxFlags = aFlags;
	if (aParent)
		SetContainerWindowL(*aParent);
	else
		{
		CreateWindowL(aParent);
		EnableDragEvents();
		Window().SetPointerGrab(ETrue);
		}
	if (iListBoxFlags & EPopout)
		{
		DrawableWindow()->EnableBackup();
		iBorder.SetType(TEikBorder::EThickDeepRaisedWithOutline);
		}
	if (iListBoxFlags & EIncrementalMatching)
		CreateMatchBufferL();
	CreateViewL();
	}

EXPORT_C void CEikListBox::ConstructL(MListBoxModel* aListBoxModel,CListItemDrawer* aListItemDrawer,const CCoeControl* aParent,TInt aFlags)
	{
	__ASSERT_DEBUG(aListBoxModel!=NULL,Panic(EEikPanicListBoxInvalidModelSpecified));
	__ASSERT_DEBUG(aListItemDrawer!=NULL,Panic(EEikPanicListBoxInvalidItemDrawerSpecified));
	iModel = aListBoxModel;
	iItemDrawer = aListItemDrawer;
	ConstructL(aParent,aFlags);
	}

EXPORT_C void CEikListBox::ConstructL(MListBoxModel* aListBoxModel, CListItemDrawer* aListItemDrawer, const CCoeControl* aParent, TEikBorder aBorder, TInt aFlags)
	{
	iBorder = aBorder;
	CEikListBox::ConstructL(aListBoxModel, aListItemDrawer, aParent, aFlags);
	}

EXPORT_C void CEikListBox::SetListBoxObserver(MEikListBoxObserver* aObserver)
	{
	iListBoxObserver = aObserver;
	}

EXPORT_C void CEikListBox::SetContainerWindowL(const CCoeControl& aParent)
    {
	if ((iListBoxFlags & ECreateOwnWindow) || (iListBoxFlags & EPopout))
		{
		CreateWindowL(&aParent);
		if (iListBoxFlags & EPopout)
			DrawableWindow()->EnableBackup();
		}
	else
		CCoeControl::SetContainerWindowL(aParent);
    EnableDragEvents();
    Window().SetPointerGrab(ETrue);
    }

EXPORT_C CListBoxView* CEikListBox::MakeViewClassInstanceL()
	{
	return (new(ELeave) CListBoxView);
	}

EXPORT_C void CEikListBox::CreateViewL()
	{
	// assert that the model and item drawer aren't null
	if (iView)
		return;
	iView = MakeViewClassInstanceL();
	iView->ConstructL(iModel, iItemDrawer, iEikonEnv->ScreenDevice(), &(iEikonEnv->RootWin()), &Window(), Rect(), iItemHeight);
	if (iListBoxFlags & EIncrementalMatching)
		{
		iView->SetMatcherCursor(ETrue);
		iView->SetMatcherCursorColor(KDefaultLbxMatcherCursorColor);
		}
	iItemDrawer->SetVerticalInterItemGap(KEikListBoxItemVGap);
	iItemDrawer->SetDrawMark((iListBoxFlags & EMultipleSelection));
	iItemDrawer->SetSymbolFont(iEikonEnv->SymbolFont());
	if (ItemExists(0))
		SetCurrentItemIndex(0);
	CheckCreateExtensionL();
	iView->SetVisibilityObserver(iListBoxExt);
	}

EXPORT_C void CEikListBox::DrawMatcherCursor() const
	{
	if (!IsMatchBuffer())
		return;
	TInt currentItemIndex = iView->CurrentItemIndex();
	if (ItemExists(currentItemIndex)) 
		{
		if (! iView->ItemIsVisible(currentItemIndex))
			ScrollToMakeItemVisible(currentItemIndex);
		iView->DrawMatcherCursor();
		}
	}

EXPORT_C void CEikListBox::DrawItem(TInt aItemIndex) const
	{
	if (!IsReadyToDraw())
		return;
	__ASSERT_ALWAYS(iView, Panic(EEikPanicListBoxNoView));
	if (iView->ItemIsVisible(aItemIndex))
		iView->DrawItem(aItemIndex);
	else 
		ScrollToMakeItemVisible(aItemIndex);
	}

EXPORT_C void CEikListBox::ScrollToMakeItemVisible(TInt aItemIndex) const 
	{
	__ASSERT_ALWAYS(iView, Panic(EEikPanicListBoxNoView));
	TBool scrollingTookPlace = iView->ScrollToMakeItemVisible(aItemIndex);
	if (scrollingTookPlace)
		UpdateScrollBarThumbs();
	}

EXPORT_C void CEikListBox::Draw(const TRect& aRect) const
    {
    CWindowGc* gc = iItemDrawer->Gc();
	iBorder.Draw(*gc,Rect());
	ClearMargins();
	iView->Draw(&aRect);
    }

EXPORT_C void CEikListBox::ClearMargins() const
	{
	if (!iView->RedrawDisabled())
		{
		CWindowGc* gc = iItemDrawer->Gc();
		if (gc)
			{
			TRect viewRect=iView->ViewRect();
			TRect clientRect;
			RestoreClientRectFromViewRect(clientRect);
			gc->SetBrushColor(iBackColor);
			EikDrawUtils::ClearBetweenRects(*gc, clientRect, viewRect);
			}
		}
	}

EXPORT_C void CEikListBox::UpdateScrollBarsL()
	{
	if (!iSBFrame)
		return;
	TEikScrollBarModel hSbarModel;
	TEikScrollBarModel vSbarModel;
	TRect rect=iView->ViewRect();
	if (!(iListBoxFlags & EScrollBarSizeExcluded))
		{
		// Ignore scrollbars presence to set the model, Scrollbar Frame will change it as required
		rect = iBorder.InnerRect(Rect());
		rect.Shrink(iHorizontalMargin, iVerticalMargin);
		AdjustRectHeightToWholeNumberOfItems(rect);
		// rect is now viewRect when ignoring scrollbars
		}
	if (iSBFrame->VScrollBarVisibility()!=CEikScrollBarFrame::EOff)
		{
		vSbarModel.iThumbPosition = iView->TopItemIndex();
		vSbarModel.iScrollSpan = iModel->NumberOfItems();
		vSbarModel.iThumbSpan = iView->NumberOfItemsThatFitInRect(rect);
		if (vSbarModel.iScrollSpan-vSbarModel.iThumbPosition<vSbarModel.iThumbSpan)
			{
			vSbarModel.iThumbPosition=Max(0,vSbarModel.iScrollSpan-vSbarModel.iThumbSpan);
			iView->ScrollToMakeItemVisible(vSbarModel.iThumbPosition); // force a scroll if neccessary
			}
		}
	if (iSBFrame->HScrollBarVisibility()!=CEikScrollBarFrame::EOff)
		{
		iView->CalcDataWidth();
		hSbarModel.iThumbPosition = iView->HScrollOffset();
		hSbarModel.iScrollSpan = iView->DataWidth();
		hSbarModel.iThumbSpan = iView->VisibleWidth(rect);
		}
	TRect clientRect;
	RestoreClientRectFromViewRect(clientRect);
	TRect inclusiveRect=Rect();
	TEikScrollBarFrameLayout layout;
	CreateScrollBarFrameLayout(layout);
	TBool sizeChanged=iSBFrame->TileL(&hSbarModel, &vSbarModel, clientRect, inclusiveRect, layout);
	if (!sizeChanged)
		return;
	// else size of client/inclusive rect has changed
	if (layout.iTilingMode==TEikScrollBarFrameLayout::EClientRectConstant)
		SetSizeWithoutNotificationL(inclusiveRect.Size());
	else
		{
		SetViewRectFromClientRect(clientRect);
		ClearMargins();
		}
	AdjustTopItemIndex();
	}
												            
void CEikListBox::CreateScrollBarFrameLayout(TEikScrollBarFrameLayout& aLayout)	const
	{
	aLayout.iInclusiveMargin=iBorder.Margins();
	aLayout.iClientMargin.iTop=aLayout.iClientMargin.iBottom=iVerticalMargin;
	aLayout.iClientMargin.iLeft=aLayout.iClientMargin.iRight=iHorizontalMargin;
	aLayout.iClientAreaGranularity=TSize(HorizScrollGranularityInPixels(), iItemHeight); 
	aLayout.iTilingMode=(!(iListBoxFlags & EScrollBarSizeExcluded))? TEikScrollBarFrameLayout::EInclusiveRectConstant : TEikScrollBarFrameLayout::EClientRectConstant;
	}

EXPORT_C TInt CEikListBox::HorizScrollGranularityInPixels() const
	{
	return 1; // horiz scroll bar model set in pixels for standard listbox
	}

EXPORT_C void CEikListBox::Reset()
	{
	((CListBoxView::CSelectionIndexArray*)iView->SelectionIndexes())->Reset();
	iView->SetTopItemIndex(0);
	iView->SetCurrentItemIndex(0);
	iView->ClearSelectionAnchorAndActiveIndex();
	iView->SetHScrollOffset(0);
	}

EXPORT_C void CEikListBox::HandleItemAdditionL()
	{
	iView->CalcDataWidth();
	iView->CalcBottomItemIndex();
	UpdateScrollBarsL();
	DrawNow();
	}

EXPORT_C void CEikListBox::HandleItemRemovalL()
	{
	// Should be called after one or more items have been removed from the model
	// It is up to the application to then make sure that the current item index is set to an appropriate value and to redraw the listbox
	Reset();
	iView->CalcBottomItemIndex();
	UpdateScrollBarsL();
	}

EXPORT_C const CArrayFix<TInt>* CEikListBox::SelectionIndexes() const
	{
	return iView->SelectionIndexes();
	}

EXPORT_C void CEikListBox::SetSelectionIndexesL(CListBoxView::CSelectionIndexArray* aArrayOfSelectionIndexes)
	{
	if (! aArrayOfSelectionIndexes)
		iView->ClearSelection();
	else
		iView->SetSelectionIndexesL(aArrayOfSelectionIndexes);
	}

void CEikListBox::HorizontalScroll(TInt aScrollAmountInPixels)
	{
	iView->HScroll(aScrollAmountInPixels);
	if (iSBFrame)
		{
		if (iSBFrame->HScrollBarVisibility()!=CEikScrollBarFrame::EOff)
			iSBFrame->MoveThumbsBy(aScrollAmountInPixels, 0);
		}
	}

EXPORT_C void CEikListBox::HandleLeftArrowKeyL(CListBoxView::TSelectionMode /*aSelectionMode*/)
	{
	HorizontalScroll(-(iView->ViewRect().Width() / KEikListBoxHNudgeSizeAsFractionOfViewRectWidth));
	}


EXPORT_C void CEikListBox::HandleRightArrowKeyL(CListBoxView::TSelectionMode /*aSelectionMode*/)
	{
	HorizontalScroll((iView->ViewRect().Width() / KEikListBoxHNudgeSizeAsFractionOfViewRectWidth));
	}


EXPORT_C TKeyResponse CEikListBox::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
	TInt topItemIndex = iView->TopItemIndex();
	if (ItemExists(topItemIndex) == EFalse) 
		return(EKeyWasConsumed);
    TInt code = aKeyEvent.iCode;
 	TBool shiftKeyPressed = (aKeyEvent.iModifiers & EModifierShift);
	TBool controlKeyPressed = (aKeyEvent.iModifiers & EModifierCtrl);
	TInt oldCurrentItemIndex = iView->CurrentItemIndex();
	TBool enterKeyPressed=EFalse;
	TBool escapeKeyPressed=EFalse;
	TBool sideBarKeyPressed=EFalse;
	CListBoxView::TSelectionMode selectionMode = CListBoxView::ESingleSelection;
	if (iListBoxFlags & EMultipleSelection)
		{
		if (shiftKeyPressed)
			selectionMode = CListBoxView::EContiguousSelection;
		else if (controlKeyPressed)
			selectionMode = CListBoxView::ENoSelection;
		}
	if (iListBoxFlags & ENoExtendedSelection)
		selectionMode = CListBoxView::ENoSelection;
	TInt oldMatcherCursorPos = iView->MatcherCursorPos();
	switch (code)
		{
	case EKeyUpArrow:
		if(!(iListBoxFlags & EPopout) && (oldCurrentItemIndex==0 || oldCurrentItemIndex==-1))
			return(EKeyWasNotConsumed);
		iView->MoveCursorL(CListBoxView::ECursorPreviousItem, selectionMode);
		ClearMatchBuffer();
		break;
	case EKeyDownArrow:
		if(!(iListBoxFlags & EPopout) && (oldCurrentItemIndex==Model()->NumberOfItems()-1 || oldCurrentItemIndex==-1))
			return(EKeyWasNotConsumed);
		iView->MoveCursorL(CListBoxView::ECursorNextItem, selectionMode);
		ClearMatchBuffer();
		break;
	case EKeyLeftArrow:
		HandleLeftArrowKeyL(selectionMode);
		break;
	case EKeyRightArrow:
		HandleRightArrowKeyL(selectionMode);
		break;
	case EKeyPageUp:
		if(!(iListBoxFlags & EPopout) && (oldCurrentItemIndex==0 || oldCurrentItemIndex==-1))
			return(EKeyWasNotConsumed);
		iView->MoveCursorL(CListBoxView::ECursorPreviousPage, selectionMode);
		ClearMatchBuffer();
		break;
	case EKeyPageDown:
		if(!(iListBoxFlags & EPopout) && (oldCurrentItemIndex==Model()->NumberOfItems()-1 || oldCurrentItemIndex==-1))
			return(EKeyWasNotConsumed);
		iView->MoveCursorL(CListBoxView::ECursorNextPage, selectionMode);
		ClearMatchBuffer();
		break;
	case EKeyHome:
		iView->MoveCursorL(CListBoxView::ECursorFirstItem, selectionMode);
		ClearMatchBuffer();
		break;
	case EKeyEnd:
		iView->MoveCursorL(CListBoxView::ECursorLastItem, selectionMode);
		ClearMatchBuffer();
		break;
	case 0:
		if (!controlKeyPressed || aType!=EEventKey)
			goto TestMatch;
		// else fall through
	case EKeySpace:
		if (iListBoxFlags & EMultipleSelection)
			{
			iView->UpdateSelectionL(CListBoxView::EDisjointSelection);
			iListBoxFlags |= EStateChanged;
			}
		break;
    case EKeyEnter:
		if (controlKeyPressed && !(aKeyEvent.iModifiers&EModifierPureKeycode))
			goto TestMatch;
        enterKeyPressed = ETrue;
        break;
	case EKeyMenu:
	case EEikSidebarMenuKey:
	case EEikSidebarClipKey:
	case EEikSidebarIrdaKey:
	case EEikSidebarZoomInKey:
	case EEikSidebarZoomOutKey:
		if (!(aKeyEvent.iModifiers&EAllStdModifiers))
			sideBarKeyPressed = ETrue;
		break;
    case EKeyEscape:
        escapeKeyPressed = ETrue;
        break;
	case EKeyBackspace:
		if (IsMatchBuffer() && iView->MatcherCursorPos())
			UndoLastChar();
		break;
	default:
TestMatch:
		if (TChar(aKeyEvent.iCode).IsPrint())
		    MatchTypedCharL(aKeyEvent.iCode);
		else
			return(EKeyWasConsumed); 
		break;
		}
	UpdateScrollBarThumbs();
	if (oldCurrentItemIndex != iView->CurrentItemIndex())
		{
		iListBoxFlags |= EStateChanged;
		DrawMatcherCursor();
		}
	else if (oldMatcherCursorPos != iView->MatcherCursorPos() && IsMatchBuffer())
		DrawMatcherCursor();

	if (iListBoxFlags & EStateChanged)
		{
		ReportEventL(MCoeControlObserver::EEventStateChanged);
		iListBoxFlags &= (~EStateChanged);
		}

	if (enterKeyPressed)
		{
		ReportListBoxEventL(MEikListBoxObserver::EEventEnterKeyPressed);
		if (iListBoxFlags & EPopout)
			ReportEventL(MCoeControlObserver::EEventRequestExit);
		}

	if (escapeKeyPressed || sideBarKeyPressed)
		if (iListBoxFlags & EPopout)
			ReportEventL(MCoeControlObserver::EEventRequestCancel);

	if (sideBarKeyPressed)
		return(EKeyWasNotConsumed);

    return(EKeyWasConsumed);
    }

EXPORT_C void CEikListBox::UpdateScrollBarThumbs() const 
	{
	if (!iSBFrame)
		return;
	TInt hThumbPos=iView->HScrollOffset();
	TInt vThumbPos=iView->TopItemIndex();
    iSBFrame->MoveHorizThumbTo(hThumbPos);
    iSBFrame->MoveVertThumbTo(vThumbPos);
	}

EXPORT_C void CEikListBox::ReportListBoxEventL(MEikListBoxObserver::TListBoxEvent aEvent)
	{
	if (iListBoxObserver)
		iListBoxObserver->HandleListBoxEventL(this, aEvent);
	}

EXPORT_C TInt CEikListBox::HorizontalNudgeValue() const
	{
	return (iView->ViewRect().Width() / KEikListBoxHNudgeSizeAsFractionOfViewRectWidth);
	}

EXPORT_C CEikScrollBarFrame* const CEikListBox::ScrollBarFrame()
	{ 
	return ((CEikScrollBarFrame* const)iSBFrame); 
	}

EXPORT_C void CEikListBox::HandleScrollEventL(CEikScrollBar* aScrollBar,TEikScrollEvent aEventType)
	{
	TInt oldThumbPos = (aEventType & KEikScrollEventBarMask) ? iView->HScrollOffset() : iView->TopItemIndex();
	TInt newThumbPos = aScrollBar->ThumbPosition();
	TInt pageSize = aScrollBar->Model()->iThumbSpan;
	TInt maxThumbPos = aScrollBar->Model()->MaxThumbPos();
	switch (aEventType & KEikScrollEventBarMask)
		{ 
	case KEikScrollEventFromHBar:
		switch (aEventType)
			{
		case EEikScrollLeft:
			newThumbPos -= HorizontalNudgeValue();
			break;
		case EEikScrollRight:
			newThumbPos += HorizontalNudgeValue();
			break;
		case EEikScrollPageLeft:
			newThumbPos -= pageSize;
			break;
		case EEikScrollPageRight:
			newThumbPos += pageSize;
			break;
		case EEikScrollThumbDragVert:
		case EEikScrollThumbReleaseVert:
			// in the case of drag events, the scrollbar automatically updates its thumb pos...
			break;
		default:
			break;
			}
		newThumbPos = Max(0, Min(newThumbPos, maxThumbPos));
		iView->HScroll(newThumbPos - oldThumbPos);
		if (aEventType != EEikScrollThumbDragHoriz)
			aScrollBar->SetModelThumbPosition(iView->HScrollOffset());
		break;
	case KEikScrollEventFromVBar:
		switch (aEventType)
			{
		case EEikScrollUp:
			--newThumbPos;
			break;
		case EEikScrollDown:
			++newThumbPos;
			break;
		case EEikScrollPageUp:
			newThumbPos -= ((pageSize < 2)? 1 : pageSize - 1);
			break;
		case EEikScrollPageDown:
			newThumbPos += ((pageSize < 2)? 1 : pageSize - 1);
			break;
		case EEikScrollThumbDragVert:
		case EEikScrollThumbReleaseVert:
			// in the case of drag events, the scrollbar automatically updates its thumb pos...
			break;
		default:
			break;
			}
		newThumbPos = Max(0, Min(newThumbPos, maxThumbPos));
		iView->VScrollTo(newThumbPos);
		if (aEventType != EEikScrollThumbDragVert)
			aScrollBar->SetModelThumbPosition(iView->TopItemIndex());
		}
	}

EXPORT_C void CEikListBox::HandleDragEventL(TPoint aPointerPos)
	{
	if (!(iListBoxFlags & ELeftDownInViewRect))
		return;
	TRect viewRect(iView->ViewRect());
	if ((aPointerPos.iX > viewRect.iBr.iX) || (aPointerPos.iX < viewRect.iTl.iX))
		aPointerPos.iX = viewRect.iTl.iX;
	TInt itemIndex;
	TBool pointerIsOverAnItem = iView->XYPosToItemIndex(aPointerPos, itemIndex);
	CListBoxView::TSelectionMode selectionMode = (iListBoxFlags & EMultipleSelection) ? CListBoxView::EContiguousSelection : CListBoxView::ESingleSelection;
	TInt oldCurrentItemIndex = iView->CurrentItemIndex();
	if (pointerIsOverAnItem)
		{
		// drag event occurred within the listbox
		if (itemIndex==oldCurrentItemIndex)
			return;
		iView->SetCurrentItemIndex(itemIndex);
		iView->DrawItem(oldCurrentItemIndex);
		iView->UpdateSelectionL(selectionMode);
		iView->DrawItem(itemIndex);
		}
	else if (viewRect.Contains(aPointerPos))
		{
		// find item nearest to the pointer pos and make that the current item
		}
	else if ((aPointerPos.iY < viewRect.iTl.iY) || (aPointerPos.iY > viewRect.iBr.iY))
		{
		// drag event occurred outside the listbox's viewRect
		TRect screenRect(TPoint(-1000, -1000), TPoint(1000, 1000));
		TRect ignoreDragRect;
		TInt oldTopItemIndex = iView->TopItemIndex();
		TInt oldBottomItemIndex = iView->BottomItemIndex();
		if (aPointerPos.iY < viewRect.iTl.iY)
			{
			ignoreDragRect.SetRect(screenRect.iTl, TPoint(screenRect.iBr.iX, viewRect.iTl.iY));
			itemIndex = ItemExists(oldTopItemIndex-1) ? (oldTopItemIndex-1) : oldTopItemIndex;
			}
		else
			{
			ignoreDragRect.SetRect(TPoint(screenRect.iTl.iX, viewRect.iBr.iY), screenRect.iBr);
			itemIndex = ItemExists(oldBottomItemIndex+1) ? (oldBottomItemIndex+1) : oldBottomItemIndex;
			}
		SetCurrentItemIndexAndDraw(itemIndex);
		UpdateScrollBarThumbs();
		Window().RequestPointerRepeatEvent(KEikListBoxPointerRepeatInterval, ignoreDragRect);
		}
	if (itemIndex != oldCurrentItemIndex)
		{
		iView->UpdateSelectionL(selectionMode);
		iListBoxFlags |= EStateChanged;
		if (IsMatchBuffer())
			{
			ClearMatchBuffer();
			DrawMatcherCursor();
			}
		}
	}

LOCAL_C void EnableRedraw(TAny* aPtr)
	{
	CListBoxView& lbv=*(CListBoxView*)aPtr;
	lbv.SetDisableRedraw(EFalse);
	}


EXPORT_C void CEikListBox::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	if (!(ItemExists(iView->TopItemIndex())))
		return;
	CheckCreateBufferL(); // don't need to create the full matching buffer here - only the iPressedIndex
	TInt itemIndex;
	TPoint pointerPos(aPointerEvent.iPosition);
	TBool pointerIsOverAnItem = iView->XYPosToItemIndex(pointerPos, itemIndex);
	TInt oldCurrentItemIndex;	
	if ((aPointerEvent.iModifiers&EModifierDoubleClick) && pointerIsOverAnItem)
		{
		ReportListBoxEventL(MEikListBoxObserver::EEventItemDoubleClicked);
		return;
		}
	CListBoxView::TSelectionMode selectionMode = CListBoxView::ESingleSelection;
	TBool shiftKeyPressed = EFalse;
	TBool controlKeyPressed = EFalse;
	if (iListBoxFlags & EMultipleSelection)
		{
		// determine selection mode
		shiftKeyPressed = (aPointerEvent.iModifiers) & EModifierShift;
		controlKeyPressed = (aPointerEvent.iModifiers) & EModifierCtrl;
		if (shiftKeyPressed)	
			selectionMode = CListBoxView::EContiguousSelection;
		else if (controlKeyPressed)
			selectionMode = CListBoxView::EDisjointSelection;
		}
	if (iListBoxFlags & ENoExtendedSelection)
		{
		controlKeyPressed = ETrue;
		selectionMode = CListBoxView::EDisjointSelection;
		}
	switch (aPointerEvent.iType)
		{
		case TPointerEvent::EButton1Down:
			if ((! (Rect().Contains(aPointerEvent.iPosition))) && (iListBoxFlags & EPopout)) 
				{
				ReportEventL(MCoeControlObserver::EEventRequestCancel);
				return;
				}
			if (iView->ViewRect().Contains(aPointerEvent.iPosition))
				iListBoxFlags|=ELeftDownInViewRect;
			else
				return;
			oldCurrentItemIndex = iView->CurrentItemIndex();
			if (pointerIsOverAnItem)
				{
				Buffer()->iPressedIndex=(itemIndex==oldCurrentItemIndex ? itemIndex : KEikListBoxInvalidIndex);
				if (!(iListBoxFlags & EMultipleSelection))		// i.e. this is a single selection listbox
					{
					if (itemIndex == oldCurrentItemIndex)
						return;
					iView->SetCurrentItemIndex(itemIndex);
					iView->DrawItem(oldCurrentItemIndex);
					iView->SetDisableRedraw(ETrue);
					iView->DeselectItem(oldCurrentItemIndex);
					CleanupStack::PushL(TCleanupItem(EnableRedraw,iView));
					iView->SelectItemL(itemIndex);
					CleanupStack::Pop();	// Redraw enabler
					iView->SetDisableRedraw(EFalse);
					iView->DrawItem(itemIndex);
					iListBoxFlags |= EStateChanged;
					}
				else	// multiple selection listbox
					{
					if ((itemIndex == oldCurrentItemIndex) && (iView->ItemIsSelected(itemIndex)) && (! controlKeyPressed))
						return;
					iView->SetCurrentItemIndex(itemIndex);
					iView->DrawItem(oldCurrentItemIndex);
					iView->UpdateSelectionL(selectionMode);
					// iView->DrawItem(itemIndex);
					iListBoxFlags |= EStateChanged;
					}
				if (itemIndex != oldCurrentItemIndex)
					{
					iListBoxFlags |= EStateChanged;
					if (IsMatchBuffer())
						{
						ClearMatchBuffer();
						DrawMatcherCursor();
						}
					}
				}
			break;
		case TPointerEvent::EButton1Up:
			if ((! (Rect().Contains(aPointerEvent.iPosition))) && (iListBoxFlags & EPopout)) 
				{
				ReportEventL(MCoeControlObserver::EEventRequestCancel);
				return;
				}
			if (!(iListBoxFlags & ELeftDownInViewRect))
				return;
			if (iListBoxFlags & EStateChanged)
				{
        		ReportEventL(MCoeControlObserver::EEventStateChanged);
				iListBoxFlags &= (~EStateChanged);
				}
			iListBoxFlags&=(~ELeftDownInViewRect);
			if (pointerIsOverAnItem)
				{
				ReportListBoxEventL(MEikListBoxObserver::EEventItemClicked);
				if ((iListBoxFlags & EPopout) && (!(shiftKeyPressed || controlKeyPressed)))
					ReportEventL(MCoeControlObserver::EEventRequestExit);
				else if ((Buffer()->iPressedIndex!=KEikListBoxInvalidIndex) && (itemIndex==Buffer()->iPressedIndex))
					ReportListBoxEventL(MEikListBoxObserver::EEventItemDoubleClicked);
				else
					Buffer()->iPressedIndex=KEikListBoxInvalidIndex;
				}
			break;
		case TPointerEvent::EDrag:
			HandleDragEventL(pointerPos);
			break;
		case TPointerEvent::EButtonRepeat:
			if (!(iListBoxFlags & ELeftDownInViewRect))
				return;
			HandleDragEventL(pointerPos);
			break;
		default:
			break;
		}
    }

EXPORT_C void CEikListBox::SimulateArrowKeyEventL(TKeyCode aKeyCode)
	{
	TKeyEvent keyEvent;
	keyEvent.iCode = aKeyCode;
	if (iListBoxFlags & EMultipleSelection)
		keyEvent.iModifiers = EModifierShift;
	OfferKeyEventL(keyEvent, EEventKey);
	}

EXPORT_C void CEikListBox::ClearSelection()
	{
	__ASSERT_DEBUG(iView, Panic(EEikPanicListBoxNoView));
	iView->ClearSelection();
	}

EXPORT_C void CEikListBox::FocusChanged(TDrawNow aDrawNow)
	{
	if (IsFocused())
		{
		iView->SetEmphasized(ETrue);
		if (IsMatchBuffer())
			iView->DrawMatcherCursor();
		}
	else
		{
		iView->SetEmphasized(EFalse);
		iView->HideMatcherCursor();
		}
    if (aDrawNow)
        {
	    // redraw items affected by change in emphasis
	    // redraw items affected by change in emphasis
		if (iListBoxFlags&EMultipleSelection)
			{
			TInt numOfSelectedItems = iView->SelectionIndexes()->Count();
			TInt selectionIndex = 0;
			for (TInt i = 0; i < numOfSelectedItems; i++)
				{
				selectionIndex = (*(iView->SelectionIndexes()))[i];
				if (ItemExists(selectionIndex))
					iView->DrawItem(selectionIndex);
				}
 			}
		else
			{
			const TInt current=CurrentItemIndex();
			if (ItemExists(current))
				iView->DrawItem(current);
			}
       }
	}

EXPORT_C void CEikListBox::SetDimmed(TBool aDimmed)
	{
	// should panic if view does not exist
	CCoeControl::SetDimmed(aDimmed);
	iView->SetDimmed(aDimmed);
	}

EXPORT_C void CEikListBox::ClearMatchBuffer() const
	{
	if(IsMatchBuffer())
		{
		iView->SetMatcherCursorPos(0);
		MatchBuffer()->Clear();
		}
	}

EXPORT_C void CEikListBox::MatchTypedCharL(TUint aCode)
	{
	if (iListBoxFlags&ENoFirstLetterMatching)
		return;
	const MDesCArray* matchableTextArray = iModel->MatchableTextArray();
	if (! matchableTextArray)
		return;
	if (IsMatchBuffer())
		{
		TInt matcherCursorPos = iView->MatcherCursorPos();
		if (MatchBuffer()->MatchLength() == KEikMaxMatchingBufferLength)
			return;
		MatchBuffer()->AppendChar(aCode);
	    TInt selectedItemIndex;
		TInt ret = MatchBuffer()->FirstMatchingIndexF(selectedItemIndex, *matchableTextArray);
		if (ret == KErrNone)
			{
			++matcherCursorPos;
/*
			if (matcherCursorPos >= matchableTextArray->MdcaPoint(selectedItemIndex).Length())
				{
				iListBoxExt->iBuffer->iMatchBuffer->DeleteLastChar();
				--matcherCursorPos;
				}
*/
			iView->VerticalMoveToItemL(selectedItemIndex, CListBoxView::ESingleSelection);
			// SetCurrentItemIndexAndDraw(selectedItemIndex);
			iView->SetMatcherCursorPos(matcherCursorPos);
			}
		else   // No match with buf with new letter: discard new char
			{		
			MatchBuffer()->DeleteLastChar();
			}
		}
	else
		{
		// do first later matching here
		TChar matchCharacter(aCode);
		matchCharacter.Fold();
		TInt currentItemIndex = iView->CurrentItemIndex();	 
		TChar firstCharOfItem;
		TBool foundMatch = EFalse;
		TInt itemIndex = currentItemIndex + 1;
		// look for match, starting at item below the current one
		while ((itemIndex != currentItemIndex) && !foundMatch)
			{
			// if end of list reached, restart search from the beginning of the list
			if (ItemExists(itemIndex) == EFalse)
				{
				itemIndex = 0;
				if (itemIndex == currentItemIndex)
					{
					foundMatch = ETrue;
					break;
					}
				}
			TPtrC buf=matchableTextArray->MdcaPoint(itemIndex);
			if (buf.Length())
				{
				firstCharOfItem = buf[0];
				firstCharOfItem.Fold();
				if (matchCharacter == firstCharOfItem)
					{
					foundMatch = ETrue;
					break;
					}
				}
			++itemIndex;
			}
		if (foundMatch)
			// SetCurrentItemIndexAndDraw(itemIndex);
			iView->VerticalMoveToItemL(itemIndex, CListBoxView::ESingleSelection);
		}
	}

EXPORT_C void CEikListBox::UndoLastChar()
	{
	__ASSERT_DEBUG(MatchBuffer(), Panic(EEikPanicListBoxNoMatchBuffer));
	__ASSERT_DEBUG(iModel->MatchableTextArray(), Panic(EEikPanicListBoxNoMatchTextArray));
	iView->SetMatcherCursorPos(iView->MatcherCursorPos() - 1);
	MatchBuffer()->DeleteLastChar();
	TInt selectedItemIndex;
	const MDesCArray* matchableTextArray = iModel->MatchableTextArray(); 
	TInt retcode = MatchBuffer()->FirstMatchingIndexF(selectedItemIndex, *matchableTextArray);
	if (!retcode)
		SetCurrentItemIndexAndDraw(selectedItemIndex);
	}

EXPORT_C void CEikListBox::SetLaunchingButton(CEikButtonBase* aButton)
	{
	iLaunchingButton=aButton;
	}

EXPORT_C TInt CEikListBox::HorizontalMargin() const
	{
	return iHorizontalMargin;
	}

EXPORT_C TInt CEikListBox::VerticalMargin() const
	{
	return iVerticalMargin;
	}

EXPORT_C void CEikListBox::SetVerticalMargin(TInt aMargin)
	{
	iVerticalMargin = aMargin;
	}

EXPORT_C void CEikListBox::SetHorizontalMargin(TInt aMargin)
	{
	iHorizontalMargin = aMargin;
	}

EXPORT_C RIncrMatcherBase* CEikListBox::MatchBuffer() const
	{
	if(CONST_CAST(CEikListBox*,this)->CheckCreateExtension() && Buffer())
		return Buffer()->iMatchBuffer;
	return NULL;
	}

EXPORT_C TInt CEikListBox::ViewRectHeightAdjustment() const
	{
	return iViewRectHeightAdjustment;
	}

EXPORT_C TRgb CEikListBox::BackColor() const
	{
	return iBackColor;
	}

EXPORT_C TInt CEikListBox::VerticalInterItemGap() const
	{
	return KEikListBoxItemVGap;
	}

EXPORT_C void CEikListBox::Reserved_1()
	{}

EXPORT_C void CEikListBox::Reserved_2()
	{}

EXPORT_C void CEikListBox::Reserved_3()
	{}

TBool CEikListBox::CheckCreateExtension()
	{
	TInt err=KErrNone;
	if (!iListBoxExt)
		TRAP(err,iListBoxExt=CListBoxExt::NewL(*this));
	return err==KErrNone;
	}

void CEikListBox::CheckCreateExtensionL()
	{
	if (!iListBoxExt)
		iListBoxExt=CListBoxExt::NewL(*this);
	}

void CEikListBox::CheckCreateBufferL()
	{
	CheckCreateExtensionL();
	iListBoxExt->CheckCreateBufferL();
	}

CMatchBuffer* CEikListBox::Buffer() const
	{
	if(CONST_CAST(CEikListBox*,this)->CheckCreateExtension())
		return iListBoxExt->Buffer();
	return NULL;
	}

TBool CEikListBox::IsMatchBuffer() const
	{
	return (CONST_CAST(CEikListBox*,this)->CheckCreateExtension() && iListBoxExt->IsMatchBuffer());
	}

// class CEikSnakingListBox

EXPORT_C CEikSnakingListBox::CEikSnakingListBox()
    {
    }

EXPORT_C CEikSnakingListBox::~CEikSnakingListBox()
    {
    }

EXPORT_C CListBoxView* CEikSnakingListBox::MakeViewClassInstanceL() 
	{
	return (new(ELeave) CSnakingListBoxView);
	}

EXPORT_C TInt CEikSnakingListBox::ColumnWidth() const
	{
	__ASSERT_DEBUG(iView, Panic(EEikPanicListBoxNoView));
	return ((CSnakingListBoxView*)iView)->ColumnWidth();
	}

EXPORT_C void CEikSnakingListBox::SetColumnWidth(TInt aColumnWidth)
	{
	__ASSERT_DEBUG(iView, Panic(EEikPanicListBoxNoView));
	((CSnakingListBoxView*)iView)->SetColumnWidth(aColumnWidth);
	}

EXPORT_C void CEikSnakingListBox::HandleLeftArrowKeyL(CListBoxView::TSelectionMode aSelectionMode)
	{
	iView->MoveCursorL(CListBoxView::ECursorPreviousColumn, aSelectionMode);
	ClearMatchBuffer();
	}

EXPORT_C void CEikSnakingListBox::HandleRightArrowKeyL(CListBoxView::TSelectionMode aSelectionMode)
	{
	iView->MoveCursorL(CListBoxView::ECursorNextColumn, aSelectionMode);
	ClearMatchBuffer();
	}

EXPORT_C TInt CEikSnakingListBox::HorizontalNudgeValue() const
	{
	return 1;	// scroll horizontal by one column when the left/right scroll arrows (i.e. the nudge buttons) are tapped
	}

EXPORT_C TInt CEikSnakingListBox::HorizScrollGranularityInPixels() const
	{
	return ColumnWidth(); // horiz scrollbar model set in columns for snaking list box
	}

EXPORT_C void CEikSnakingListBox::SetTopItemIndex(TInt aItemIndex) const
	{
	__ASSERT_DEBUG(iView, Panic(EEikPanicListBoxNoView));
	iView->SetTopItemIndex(aItemIndex);
	}

EXPORT_C void CEikSnakingListBox::HandleViewRectSizeChangeL()
	{
	iView->CalcBottomItemIndex();
	TInt oldTopItemIndex = TopItemIndex();
	TInt newTopItemIndex = TopItemIndex();
	TInt currentItemIndex = CurrentItemIndex();
	TInt numOfItemsPerColumn = 0;	
	UpdateScrollBarsL();
	numOfItemsPerColumn = iView->ViewRect().Height() / iItemHeight;
	numOfItemsPerColumn = Max(1, numOfItemsPerColumn);
	if (currentItemIndex != oldTopItemIndex)
		{
		TInt colIndexOfTargetItem = currentItemIndex / numOfItemsPerColumn;
		TInt numOfColsThatFitInViewRect = iView->VisibleWidth(iView->ViewRect());
		TInt adjustment = newTopItemIndex % numOfItemsPerColumn;
		if (adjustment != 0)
			// adjust newTopItemIndex till it refers to the index of an item at the top of a column
			newTopItemIndex -= adjustment;
		TInt newBottomItemIndex = newTopItemIndex + (numOfColsThatFitInViewRect * numOfItemsPerColumn) - 1;
		if (currentItemIndex < newTopItemIndex)
			newTopItemIndex = colIndexOfTargetItem * numOfItemsPerColumn;
		else if (currentItemIndex > newBottomItemIndex)
			{
			TInt colIndexOfNewBottomItem = colIndexOfTargetItem;
			TInt colIndexOfNewTopItem = colIndexOfNewBottomItem - (numOfColsThatFitInViewRect - 1);
			newTopItemIndex = colIndexOfNewTopItem * numOfItemsPerColumn;
			}
		}
	else if ((newTopItemIndex != 0) && (numOfItemsPerColumn != 0))
		{
		TInt adjustment = newTopItemIndex % numOfItemsPerColumn;
		if (adjustment != 0)
			// adjust newTopItemIndex till it refers to the index of an item at the top of a column
			newTopItemIndex -= adjustment;
		}
	SetTopItemIndex(newTopItemIndex);
	iView->CalcDataWidth();
	UpdateScrollBarsL();
	iView->CalcBottomItemIndex();
	}

EXPORT_C void CEikSnakingListBox::SizeChangedL()
    {
	TRect clientRect = iBorder.InnerRect(Rect());
	SetViewRectFromClientRect(clientRect);
	HandleViewRectSizeChangeL();
	}

EXPORT_C void CEikSnakingListBox::AdjustTopItemIndex() const
	{
	// assumes we know # of items in the model
	TInt numOfItemsPerCol = iView->ViewRect().Height() / iItemHeight;
	numOfItemsPerCol = Max(1, numOfItemsPerCol);
	TInt numOfVisCols = iView->VisibleWidth(iView->ViewRect());
	TInt numOfItems = iModel->NumberOfItems();
	TInt colIndexOfRightmostCol = numOfItems / numOfItemsPerCol;
	TInt maxTopItemIndex = Max (0, (colIndexOfRightmostCol - (numOfVisCols - 1)) * numOfItemsPerCol);
	if (iView->TopItemIndex() > maxTopItemIndex)
		SetTopItemIndex(maxTopItemIndex);
	}

EXPORT_C void CEikSnakingListBox::HandleDragEventL(TPoint aPointerPos)
	{
	if (!(iListBoxFlags & ELeftDownInViewRect))
		return;
	TRect ignoreDragRect(TPoint(aPointerPos.iX-20, aPointerPos.iY-20), TPoint(aPointerPos.iX+20, aPointerPos.iY+20));
	TRect viewRect(iView->ViewRect());
	TInt itemIndex;
	TBool pointerIsOverAnItem = iView->XYPosToItemIndex(aPointerPos, itemIndex);
	CListBoxView::TSelectionMode selectionMode = (iListBoxFlags & EMultipleSelection) ? CListBoxView::EContiguousSelection : CListBoxView::ESingleSelection;
	TInt oldCurrentItemIndex = iView->CurrentItemIndex();
	TRect currentItemRect(iView->ItemPos(oldCurrentItemIndex), iView->ItemSize(oldCurrentItemIndex));
	if (pointerIsOverAnItem)
		{
		// drag event occurred within the listbox
		iView->SetCurrentItemIndex(itemIndex);
		if (itemIndex != oldCurrentItemIndex) 
			{
			iView->SetCurrentItemIndex(itemIndex);
			iView->DrawItem(oldCurrentItemIndex);
			iView->UpdateSelectionL(selectionMode);
			iView->DrawItem(itemIndex);
			}
		}
	else if ((aPointerPos.iX < viewRect.iTl.iX) || (aPointerPos.iX > viewRect.iBr.iX))
		{
		// drag event occurred outside the listbox's viewRect
		if (aPointerPos.iX < viewRect.iTl.iX)
			iView->MoveCursorL(CListBoxView::ECursorPreviousColumn, selectionMode);
		else if (aPointerPos.iX > viewRect.iBr.iX)
			iView->MoveCursorL(CListBoxView::ECursorNextColumn, selectionMode);
		MoveToNextOrPreviousItemL(aPointerPos);		
		UpdateScrollBarThumbs();
		Window().RequestPointerRepeatEvent(KEikListBoxPointerRepeatInterval, ignoreDragRect);
		}
	else
		{
		// find item nearest to the pointer pos and make that the current item
		if (viewRect.Contains(aPointerPos))
			{
			}
		else
			{
			if (aPointerPos.iX > currentItemRect.iBr.iX)
				iView->MoveCursorL(CListBoxView::ECursorNextColumn, selectionMode);
			else if (aPointerPos.iX < currentItemRect.iTl.iX)
				iView->MoveCursorL(CListBoxView::ECursorPreviousColumn, selectionMode);
			MoveToNextOrPreviousItemL(aPointerPos);
			UpdateScrollBarThumbs();
			Window().RequestPointerRepeatEvent(KEikListBoxPointerRepeatInterval, ignoreDragRect);
			}
		}
	if (iView->CurrentItemIndex() != oldCurrentItemIndex)
		{
		iListBoxFlags |= EStateChanged;
		if (IsMatchBuffer())
			{
			ClearMatchBuffer();
			DrawMatcherCursor();
			}
		}
	}

EXPORT_C void CEikSnakingListBox::MoveToNextOrPreviousItemL(TPoint aPointerPos)
	{
	CListBoxView::TSelectionMode selectionMode = (iListBoxFlags & EMultipleSelection) ? CListBoxView::EContiguousSelection : CListBoxView::ESingleSelection;
	TInt cix = iView->CurrentItemIndex();
	TRect currentItemRect(iView->ItemPos(cix), iView->ItemSize(cix));
	TInt numOfRows =  ((CSnakingListBoxView*)iView)->NumberOfItemsPerColumn();
	TBool currItemIsInLastRow = ((cix % numOfRows) == (numOfRows-1));
	TBool currItemIsLastItem = (cix == (iModel->NumberOfItems()-1));
	TBool currItemIsInFirstRow = ((cix % numOfRows) == 0);
	if ((aPointerPos.iY > currentItemRect.iBr.iY) && (! (currItemIsInLastRow || currItemIsLastItem)))
		iView->MoveCursorL(CListBoxView::ECursorNextItem, selectionMode);
	else if ((aPointerPos.iY < currentItemRect.iTl.iY) && (! currItemIsInFirstRow))
		iView->MoveCursorL(CListBoxView::ECursorPreviousItem, selectionMode);
	}

EXPORT_C void CEikSnakingListBox::RestoreClientRectFromViewRect(TRect& aClientRect) const
	{
	aClientRect=iView->ViewRect();
	aClientRect.Grow(HorizontalMargin(), VerticalMargin());
	if (!ViewRectHeightAdjustment())
		return;
	aClientRect.iBr.iY += ViewRectHeightAdjustment();
	}

EXPORT_C TInt CEikSnakingListBox::AdjustRectHeightToWholeNumberOfItems(TRect& aRect) const
	{
	TInt remainder = aRect.Height() % iItemHeight;
	if (remainder != 0) 
		aRect.iBr.iY -= remainder;
	return remainder;
	}

EXPORT_C void CEikSnakingListBox::Reserved_1()
	{}

EXPORT_C void CEikSnakingListBox::Reserved_2()
	{}

EXPORT_C void CEikSnakingListBox::Reserved_3()
	{}
