// EIKCLBD.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikclbd.h>
#include <w32std.h>
#include <gdi.h>
#include <eikenv.h>
#include <eiktxtut.h>
#include <eikdutil.h>
#include <eikpanic.h>

const TInt KColumnListBoxGranularity=4;

//
//	class CColumnListBoxData
//

EXPORT_C CColumnListBoxData* CColumnListBoxData::NewL()
//
//	Public c'tor
//
	{
	CColumnListBoxData* self=new(ELeave) CColumnListBoxData;
	self->ConstructLD();
	return(self);
	}

CColumnListBoxData::CColumnListBoxData()
//
//	Private c'tor
//
	{
	__DECLARE_NAME(_S("CColumnListBoxData"));
	}

EXPORT_C CColumnListBoxData::~CColumnListBoxData()
//
//	D'tor
//
	{
	delete iColumnArray;
	if (iBitmapArray)
		{
		iBitmapArray->ResetAndDestroy();
		delete iBitmapArray;
		}
	}

void CColumnListBoxData::ConstructLD()
//
//	Deferred c'tor
//
	{
	iColumnArray=new CArrayFixFlat<SColumn>(KColumnListBoxGranularity);
	if (iColumnArray==NULL)
		{
		delete(this);
		User::Leave(KErrNoMemory);
		}
	}

EXPORT_C TInt CColumnListBoxData::LastColumn() const
//
//	The last column defined
//
	{
	TInt count=iColumnArray->Count();
	if (!count)
		return(KErrNotFound);
	return(At(count-1).iColumn);
	}

EXPORT_C TInt CColumnListBoxData::ColumnWidthPixel(TInt aColumn) const
//
//	Return the width for a column
//
	{
	TInt index;
	if (FindColumnIndex(index,aColumn)==KErrNotFound)
		return(0);
	return(At(index).iWidth);
	}

EXPORT_C void CColumnListBoxData::SetColumnWidthPixelL(TInt aColumn,TInt aWidth)
//
//	Set a columns width
//
	{
	TInt index;
	FindColumnIndexOrAddL(index,aColumn);
	At(index).iWidth=aWidth;
	}

EXPORT_C const CFont* CColumnListBoxData::ColumnFont(TInt aColumn) const
//
//	Return the font for a column
//
	{
	TInt index;
	if (FindColumnIndex(index,aColumn)==KErrNotFound)
		return(NULL);
	return(iColumnArray->At(index).iFont);
	}

EXPORT_C void CColumnListBoxData::SetColumnFontL(TInt aColumn,const CFont* aFont)
//
//	Set a font for a column
//
	{
	TInt index;
	FindColumnIndexOrAddL(index,aColumn);
	At(index).iFont=aFont;
	}

EXPORT_C CGraphicsContext::TTextAlign CColumnListBoxData::ColumnAlignment(TInt aColumn) const
//
//	Return a columns alignment
//
	{
	TInt index;
	if (FindColumnIndex(index,aColumn)==KErrNotFound)
		return(CGraphicsContext::ELeft);
	return(iColumnArray->At(index).iAlign);
	}

EXPORT_C void CColumnListBoxData::SetColumnAlignmentL(TInt aColumn,CGraphicsContext::TTextAlign aAlign)
//
//	Set a columns alignment
//
	{
	TInt index;
	FindColumnIndexOrAddL(index,aColumn);
	At(index).iAlign=aAlign;
	}

EXPORT_C TBool CColumnListBoxData::ColumnIsGraphics(TInt aColumn) const
//
//	Return true if the column contains graphics
//
	{
	TInt index;
	if (FindColumnIndex(index,aColumn)==KErrNotFound)
		return(EFalse);
	return(iColumnArray->At(index).iGraphics);
	}

EXPORT_C void CColumnListBoxData::SetGraphicsColumnL(TInt aColumn,TBool aIsGraphics)
//
//	Sets whether a column shows graphics
//
	{
	TInt index;
	FindColumnIndexOrAddL(index,aColumn);
	At(index).iGraphics=aIsGraphics;
	}

EXPORT_C CArrayPtr<CFbsBitmap>* CColumnListBoxData::BitmapArray() const
//
//	Return a pointer to the array of bitmaps
//
	{
	return iBitmapArray;
	}

EXPORT_C void CColumnListBoxData::SetBitmapArray(CArrayPtr<CFbsBitmap>* aArray)
//
//	Sets the array of bitmaps (assumes any previous array has been deleted by the caller)
//
	{
	iBitmapArray=aArray;
	}


EXPORT_C void CColumnListBoxData::Draw(CWindowGc& aGc,const TDesC* aText,const TRect& aRect,TBool aHighlight) const
//
// Draw a row
//
	{
   	aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	aGc.SetPenStyle(CGraphicsContext::ESolidPen);
	TInt lastColumn=LastColumn();
	if (lastColumn==KErrNotFound)
		{
		aGc.DrawText(TPtrC(),aRect,0); // use draw text so that dont need to change pen color/style
		return;
		}
	const CFont* font=ColumnFont(0);
	CEikonEnv* eikonEnv=CEikonEnv::Static();
	if (font==NULL)
		font=eikonEnv->NormalFont();
	TInt extraVerticalSpace=(aRect.Height()-font->HeightInPixels());
	TInt baseLineOffset=extraVerticalSpace/2+font->AscentInPixels();
	TRect textRect=aRect;
	textRect.iBr.iX=aRect.iTl.iX;
	TInt column=0;
	TPtrC text;

	FOREVER
		{
		if (textRect.iBr.iX==aRect.iBr.iX)
			break;
		textRect.iBr.iX=(column>lastColumn)? aRect.iBr.iX : Min(aRect.iBr.iX,textRect.iTl.iX+ColumnWidthPixel(column));
		if (textRect.iBr.iX!=textRect.iTl.iX)
			{
			TextUtils::ColumnText(text,column,aText);
			CGraphicsContext::TTextAlign align=ColumnAlignment(column);
			if (!ColumnIsGraphics(column))
				{
				aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
				aGc.SetPenStyle(CGraphicsContext::ESolidPen);

				if (aHighlight)
					{
					TInt gray;
					TInt color;
					TDisplayMode mode = eikonEnv->WsSession().GetDefModeMaxNumColors(gray, color);
					if (mode <= EGray256)
						{
						aGc.SetBrushColor(KRgbWhite); 
						aGc.SetDrawMode(CGraphicsContext::EDrawModeNOTPEN);
						}
					else
						{
						aGc.SetPenColor(eikonEnv->Color(EEikColorControlHighlightText));
						aGc.SetBrushColor(eikonEnv->Color(EEikColorControlHighlightBackground));
						}
					}
				else
					{
					aGc.SetPenColor(eikonEnv->Color(EEikColorControlText)); 
					aGc.SetBrushColor(eikonEnv->Color(EEikColorControlBackground));
					}
				const CFont* colFont=ColumnFont(column);
				aGc.UseFont((colFont)? colFont : font);
				aGc.DrawText(text,textRect,baseLineOffset,align);
				}
			else
				{
				if (aHighlight &&  (LastColumn()==0))
					aGc.SetBrushColor(eikonEnv->Color(EEikColorControlHighlightBackground));
				else
					aGc.SetBrushColor(eikonEnv->Color(EEikColorControlBackground));

				TLex lex(text);
				TInt index;
				__ASSERT_ALWAYS(lex.Val(index)==KErrNone,Panic(EEikPanicColumnListInvalidBitmapIndex));
				__ASSERT_DEBUG((index>=0 && index<iBitmapArray->Count()),Panic(EEikPanicColumnListInvalidBitmapIndex));
				TRect bmpRect;
				bmpRect.iTl=textRect.iTl;
				if (index>=0)
					{
					CFbsBitmap* bitmap= (*iBitmapArray)[index];
					const TSize size=bitmap->SizeInPixels();
					TPoint bmpPos=aRect.iTl;
					bmpPos.iY+=(aRect.Height()-size.iHeight)>>1;
					switch (align)
						{
					case ELeft:
						break;
					case ECenter:
						bmpPos.iX+=(textRect.Width()-size.iWidth)>>1;
						break;
					case ERight:
						bmpPos.iX=textRect.iBr.iX-size.iWidth;
						break;
						}
					bmpRect=TRect(bmpPos,size);
					aGc.BitBlt(bmpPos, bitmap);
					TInt gray;
					TInt colors;
					TDisplayMode mode = eikonEnv->WsSession().GetDefModeMaxNumColors(gray, colors);
					if (aHighlight && (LastColumn()==0))
						{
						if (mode <= EGray256)
							{
							aGc.SetBrushColor(eikonEnv->Color(EEikColorControlHighlightBackground));
							aGc.SetPenColor(eikonEnv->Color(EEikColorControlHighlightText));
							aGc.SetDrawMode(CGraphicsContext::EDrawModeNOTPEN);
							aGc.BitBlt(bmpPos, bitmap);
							aGc.SetDrawMode(CGraphicsContext::EDrawModePEN);
							}
						else
							{
							TRgb color[4];
							color[0] = KRgbWhite;
							color[1] = eikonEnv->Color(EEikColorControlHighlightBackground);
 							color[2] = KRgbBlack;
							color[3] = eikonEnv->Color(EEikColorControlHighlightText);
							aGc.MapColors(bmpRect, color, 2, ETrue);
							aGc.BitBlt(bmpPos, bitmap);
							}
						}
					else if (mode > EGray256)
						{
						TRgb color[2];
						color[0] = KRgbWhite;
						color[1] = eikonEnv->Color(EEikColorControlBackground);
						aGc.MapColors(bmpRect, color, 2, ETrue);
						}
					else
						{
						aGc.BitBlt(bmpPos, bitmap);
						}
					}
				EikDrawUtils::ClearBetweenRects(aGc,textRect,bmpRect);
				aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
				aGc.SetPenStyle(CGraphicsContext::ESolidPen);
				}
			}
		textRect.iTl.iX=textRect.iBr.iX;
		++column;
		}
	aGc.Reset();
	}


void CColumnListBoxData::AddColumnL(TInt aColumn)
//
//	Add a column's worth of data
//
	{
	SColumn column;
	column.iColumn=aColumn;
	column.iWidth=0;
	column.iAlign=CGraphicsContext::ELeft;
	column.iGraphics=EFalse;
	column.iFont=NULL;
	TKeyArrayFix key(0,ECmpTInt);
	iColumnArray->InsertIsqL(column,key);
	}

CColumnListBoxData::SColumn& CColumnListBoxData::At(TInt aArrayIndex)
//
//	Return a column of data
//
	{
	__ASSERT_DEBUG(aArrayIndex>=0 && aArrayIndex<iColumnArray->Count(),Panic(EEikPanicOutOfRange));
	return(iColumnArray->At(aArrayIndex));
	}

const CColumnListBoxData::SColumn& CColumnListBoxData::At(TInt aArrayIndex) const
//
//	Return a column of data
//
	{
	__ASSERT_DEBUG(aArrayIndex>=0 && aArrayIndex<iColumnArray->Count(),Panic(EEikPanicOutOfRange));
	return(iColumnArray->At(aArrayIndex));
	}

TInt CColumnListBoxData::FindColumnIndex(TInt& aArrayIndex,TInt aColumn) const
//
//	Find a column if it has been set
//
	{
	if (aColumn<0 || iColumnArray->Count()==0)
		return(KErrNotFound);
	TKeyArrayFix key(0,ECmpTInt);
	SColumn column;
	column.iColumn=aColumn;
	return(iColumnArray->FindIsq(column,key,aArrayIndex));
	}

void CColumnListBoxData::FindColumnIndexOrAddL(TInt& aArrayIndex,TInt aColumn)
//
//	Find a column or add it
//
	{
	if (FindColumnIndex(aArrayIndex,aColumn)!=0)
		{
		AddColumnL(aColumn);
		FindColumnIndex(aArrayIndex,aColumn);
		}
	}
