// TGRID.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <basched.h>
#include <grdstd.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikdialg.h>
#include <eikmenup.h>
#include <eikmenu.hrh>
#include <eikcmds.hrh>
#include <eikgrid.h>
#include <eikmfne.h>
#include <eikapp.h>
#include <eikdoc.h>
#include "tgrid.hrh"
#include "tgrid.rsg"

class CTestCellImg;
class CTestLabelImg;
class MGridTable;

class CTestGridAppUi : public CEikAppUi
	{
public:
	enum
		{
		ENoRows=10,ENoCols=20
		};
	enum
		{
		EGridXPos=40,EGridYPos=40,
		EGridWidth=560,EGridHeight=160
		};
public:
	~CTestGridAppUi();
	void ConstructL();
    virtual void HandleCommandL(TInt aCommand);
	virtual void DynInitMenuPaneL(TInt aMenuId,CEikMenuPane* aMenuPane);
	CEikGrid* GridWin();
private:
	void SetZoomFactorL(TInt aZoomFactor);
private:
	CTestCellImg* iTestCellImg;
	CTestLabelImg* iTestLabelImg;	
	MGridTable* iGridTable;
	CEikGrid *iGridWin;
	CGridLay* iGridLay;
	CGridImg* iGridImg;
	TZoomFactor* iZoomFactor;
	};


class CAddRangeDialog : public CEikDialog
	{
public:
	CAddRangeDialog(CEikGrid* aGridWin);
private:
    virtual void PreLayoutDynInitL();
	virtual TBool OkToExitL(TInt aButtonId);
private:
	CEikGrid* iGridWin;
	};

class COptionsDialog : public CEikDialog
	{
public:
	COptionsDialog(CEikGrid* aGridWin);
private:
    virtual void PreLayoutDynInitL();
	virtual TBool OkToExitL(TInt aButtonId);
private:
	CEikGrid* iGridWin;
	};


class CTestCellImg : public CGridCellImg
	{
public:
	CTestCellImg(const CFont *aFont);
	virtual void DrawL(CGraphicsContext *aGc,const TCellRef &aCell,const TRect& aDrawRect,
		const TRect& aClipRect) const;
private:
	const TDesC* GetL(TInt aRow,TInt aCol) const;
	CTestCellImg& operator=(const CTestCellImg&);//not implemented
private:
	enum { ENumberOfItems=5 };
private:
	const CFont* iFont;
	struct STestData
		{
		TCellRef iPos;
		TBuf<32> iBuf;
		};
	STestData iData[ENumberOfItems];	//!!! Very crude but only for testing purposes
	};


class CTestLabelImg : public CGridLabelImg
	{
public:
	CTestLabelImg(const TFontSpec& aFontSpec,MGraphicsDeviceMap* aGraphicsDeviceMap);
protected:
	virtual void DrawRowLabelL(CGraphicsContext* aGc,TInt aRow,const TRect &aRect) const;
	virtual void DrawColLabelL(CGraphicsContext* aGc,TInt aCol,const TRect &aRect) const;
	void DrawText(CGraphicsContext* aGc,const TDesC& aDes,const TRect& aRect) const;
	};

//////////////////////////////////////////

CTestGridAppUi::~CTestGridAppUi()
	{
	delete iGridWin;
    delete iGridImg;
    delete iGridLay;
	delete iTestCellImg;
	delete iTestLabelImg;
	delete iGridTable;
	delete iZoomFactor;
	}

void CTestGridAppUi::ConstructL()
	{
	BaseConstructL();
    User::Heap().Check();
	CreateHotKeyControlL(TESTGRID_HOT_KEYS);

	CGraphicsDevice* device=iCoeEnv->ScreenDevice();
	iZoomFactor = new(ELeave) TZoomFactor(device);

	iTestCellImg = new(ELeave) CTestCellImg(iCoeEnv->NormalFont());

	TFontSpec fontSpec(_L("Arial"),240);
	iTestLabelImg = new(ELeave) CTestLabelImg(fontSpec,iZoomFactor);
	iTestLabelImg->ConstructL();

	iGridLay = new(ELeave) CGridLay(iZoomFactor);
	iGridImg = CGridImg::NewL(device,iTestCellImg,iGridLay);
	iGridImg->SetGridLabelImg(iTestLabelImg);
	iGridTable = new(ELeave) MGridTable();
	iGridLay->ConstructL(iGridTable,iGridImg,ENoRows,ENoCols);

	iGridWin = CEikGrid::NewL(NULL,iGridLay,iGridImg);
	iGridWin->SetExtentL(TPoint(EGridXPos,EGridYPos),TSize(EGridWidth,EGridHeight));
	iGridLay->SetColumnBursting(ETrue);

	AddToStackL(iGridWin);
	iGridWin->ActivateL();
    User::Heap().Check();
	}

void CTestGridAppUi::HandleCommandL(TInt aCommand)
	{
	switch (aCommand)
		{
	case ECmdResetGrid:
		iGridWin->GridLay()->SetGridToDefault();
		iGridWin->DrawNow();
		iGridWin->SetCursorPosL(iGridWin->GridLay()->VisibleRange().iFrom);
		break;
	case ECmdToggleTitleLines:
		iGridWin->GridLay()->ToggleTitleLinesL();
		iGridWin->CheckScrollBarPosL();
		break;
	case ECmdAddRange:
		{
		CAddRangeDialog* dialog = new(ELeave) CAddRangeDialog(iGridWin);
		dialog->ExecuteLD(ADD_RANGE_DIALOG);
		}
		break;
	case ECmdOptions:
		{
		COptionsDialog* dialog = new(ELeave) COptionsDialog(iGridWin);
		dialog->ExecuteLD(OPTIONS_DIALOG);
		}
		break;
	case ECmdZoomIn:
		{
		TInt zoomFactor=iZoomFactor->ZoomFactor();
		zoomFactor=(zoomFactor<(TZoomFactor::EZoomOneToOne*4))
			? zoomFactor*2 : TZoomFactor::EZoomOneToOne/4;
		SetZoomFactorL(zoomFactor);
		break;
		}
	case ECmdZoomOut:
		{
		TInt zoomFactor=iZoomFactor->ZoomFactor();
		zoomFactor=(zoomFactor>(TZoomFactor::EZoomOneToOne/4))
			? zoomFactor/2 : TZoomFactor::EZoomOneToOne*4;
		SetZoomFactorL(zoomFactor);
		break;
		}
	case EEikCmdExit:
		iCoeEnv->Flush();
		CBaActiveScheduler::Exit();
		break;
		}
	}

void CTestGridAppUi::DynInitMenuPaneL(TInt aMenuId,CEikMenuPane* aMenuPane)
	{
	if (aMenuId==TESTGRID_MENU_TEST)
		{
		if (iGridWin->GridLay()->IsTitleLines())
			aMenuPane->SetItemButtonState(ECmdToggleTitleLines,EEikMenuItemSymbolOn);
		}
	}

void CTestGridAppUi::SetZoomFactorL(TInt aZoomFactor)
	{
	iZoomFactor->SetZoomFactor(aZoomFactor);
	iGridWin->UpdateGridAfterZoomL();
	}

/////////////////////////////////////////////////////////

CAddRangeDialog::CAddRangeDialog(CEikGrid* aGridWin)
	: iGridWin(aGridWin)
	{}

void CAddRangeDialog::PreLayoutDynInitL()
	{
	TRangeRef gridRange=iGridWin->GridLay()->GridRange();	
	gridRange.iFrom.Offset(1,1);	// 1 based
	gridRange.iTo.Offset(1,1);
	SetRangeEditorMinAndMax(ECtrlIdRowRange,gridRange.iFrom.iRow,gridRange.iTo.iRow);
	SetRangeEditorMinAndMax(ECtrlIdColRange,gridRange.iFrom.iCol,gridRange.iTo.iCol);
	}

TBool CAddRangeDialog::OkToExitL(TInt /*aButtonId*/)
	{
	SEikRange rowRange=RangeEditorValue(ECtrlIdRowRange);
	SEikRange colRange=RangeEditorValue(ECtrlIdColRange);
	TRangeRef gridRange(rowRange.iLowerLimit-1,colRange.iLowerLimit-1,
		rowRange.iUpperLimit-1,colRange.iUpperLimit-1);
	iGridWin->GridImg()->AddRangeToSelectedL(gridRange,CGridImg::ESelectAppend);
	return ETrue;
	}

//////////////////////////////////////////////////////////

COptionsDialog::COptionsDialog(CEikGrid* aGridWin)
	: iGridWin(aGridWin)
	{}

void COptionsDialog::PreLayoutDynInitL()
	{
	CGridLay *gridLay = iGridWin->GridLay();
	SetCheckBoxState(ECtlIdVertGridLines,gridLay->IsVerticalGridLines() 
		? CEikButtonBase::ESet : CEikButtonBase::EClear);
	SetCheckBoxState(ECtlIdHorzGridLines,gridLay->IsHorizontalGridLines() 
		? CEikButtonBase::ESet : CEikButtonBase::EClear);
	SetCheckBoxState(ECtlIdTopGridLabels,gridLay->IsTopLabels() 
		? CEikButtonBase::ESet : CEikButtonBase::EClear);
	SetCheckBoxState(ECtlIdSideGridLabels,gridLay->IsSideLabels() 
		? CEikButtonBase::ESet : CEikButtonBase::EClear);
	}

TBool COptionsDialog::OkToExitL(TInt /*aButtonId*/)
	{
	CGridLay *gridLay = iGridWin->GridLay();
	gridLay->SetVerticalGridLines(CheckBoxState(ECtlIdVertGridLines)==CEikButtonBase::ESet);
	gridLay->SetHorizontalGridLines(CheckBoxState(ECtlIdHorzGridLines)==CEikButtonBase::ESet);
	gridLay->SetTopLabels(CheckBoxState(ECtlIdTopGridLabels)==CEikButtonBase::ESet);
	gridLay->SetSideLabels(CheckBoxState(ECtlIdSideGridLabels)==CEikButtonBase::ESet);

	gridLay->ExposeCell(iGridWin->CursorPos());
	iGridWin->DrawNow();
	iGridWin->CheckScrollBarPosL();
	return ETrue;
	}

///////////////////////////////////////////////////////

CTestCellImg::CTestCellImg(const CFont *aFont)
	: iFont(aFont)
	{
	__DECLARE_NAME(_S("CTestCellImg"));
	iData[0].iPos=TCellRef(2,2);
	iData[0].iBuf=_L("Some");
	iData[1].iPos=TCellRef(2,4);
	iData[1].iBuf=_L("Hard");
	iData[2].iPos=TCellRef(3,3);
	iData[2].iBuf=_L("Coded");
	iData[3].iPos=TCellRef(4,2);
	iData[3].iBuf=_L("Test");
	iData[4].iPos=TCellRef(4,4);
	iData[4].iBuf=_L("Data");
	}

void CTestCellImg::DrawL(CGraphicsContext* aGc,const TCellRef& aCell,const TRect& aDrawRect,const TRect& aClipRect) const
	{
	const TDesC* des=GetL(aCell.iRow,aCell.iCol-BurstColOffset());
	if (des==NULL)
		return;
	TInt offset = aDrawRect.Height()-iFont->DescentInPixels();
	TRect effectiveRect=aDrawRect;
	effectiveRect.iTl.iX-=BurstLeft();
	effectiveRect.iBr.iX+=BurstRight();
	aGc->UseFont(iFont);
	aGc->SetPenColor(KRgbGridForeground);
	TRect realClipRect=aDrawRect;
	realClipRect.Grow(1,1);
	realClipRect.Intersection(effectiveRect);
	realClipRect.Intersection(aClipRect);
	aGc->SetClippingRect(realClipRect);
	aGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
	aGc->SetBrushColor(KRgbGridBackground);
	aGc->DrawText(*des,effectiveRect,offset,CGraphicsContext::ELeft);
	aGc->CancelClippingRect();
	aGc->DiscardFont();
	}

const TDesC* CTestCellImg::GetL(TInt aRow,TInt aCol) const
//
// Horrible array access function but OK for low ENumberOfItems
	{
	for (TInt ii=0;ii<ENumberOfItems;ii++)
		{
		if (iData[ii].iPos.iRow==aRow && iData[ii].iPos.iCol==aCol)
			return &iData[ii].iBuf;
		}
	return NULL;
	}

////////////////////////////////////////////////////////////

CTestLabelImg::CTestLabelImg(const TFontSpec& aFontSpec,MGraphicsDeviceMap* aGraphicsDeviceMap)
	: CGridLabelImg(aFontSpec,aGraphicsDeviceMap)
	{
	__DECLARE_NAME(_S("CTestLabelImg"));
	}

void CTestLabelImg::DrawRowLabelL(CGraphicsContext* aGc,TInt aRow,const TRect &aRect) const
	{
	TBuf<32> buf;
	buf.Num(aRow+1);
	DrawText(aGc,buf,aRect);
	}

void CTestLabelImg::DrawColLabelL(CGraphicsContext* aGc,TInt aCol,const TRect &aRect) const
	{
	TBuf<32> buf;
	if (aCol>25)
		buf.Append(aCol/26+'A'-1);
	buf.Append(aCol%26+'A');
	DrawText(aGc,buf,aRect);
	}

void CTestLabelImg::DrawText(CGraphicsContext* aGc,const TDesC& aDes,const TRect& aRect) const
	{
	aGc->SetPenColor(KRgbGridBackground);
	aGc->DrawLine(aRect.iTl,TPoint(aRect.iBr.iX,aRect.iTl.iY));
	aGc->DrawLine(aRect.iTl,TPoint(aRect.iTl.iX,aRect.iBr.iY));
	TRect rect=aRect;
	rect.iTl+=TPoint(1,1);
	TInt offset = rect.Height()-iFont->DescentInPixels();
	aGc->SetPenColor(KRgbGridForeground);
	aGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
	aGc->SetBrushColor(KRgbGridBackground); // is this the correct colour ???
	aGc->UseFont(iFont);
	aGc->DrawText(aDes,rect,offset,CGraphicsContext::ECenter);
	aGc->SetBrushStyle(CGraphicsContext::ENullBrush);
	}

////////////////////////////////////////////////////////////////

//
// CTestGridDocument
//

class CTestGridDocument : public CEikDocument
	{
public:
	CTestGridDocument(CEikApplication& aApp): CEikDocument(aApp) { }
private: // from CApaDocument
	CEikAppUi* CreateAppUiL();
	};

CEikAppUi* CTestGridDocument::CreateAppUiL()
	{
    return(new(ELeave) CTestGridAppUi);
	}

//
// CTestGridApplication
//

class CTestGridApplication : public CEikApplication
	{
private: // from CApaApplication
	CApaDocument* CreateDocumentL();
	TUid AppDllUid() const;
	};

const TUid KUidTestGridApp={229};

TUid CTestGridApplication::AppDllUid() const
	{
	return(KUidTestGridApp);
	}

CApaDocument* CTestGridApplication::CreateDocumentL()
	{
	return(new(ELeave) CTestGridDocument(*this));
	}

//
// EXPORTed functions
//

EXPORT_C CApaApplication* NewApplication()
	{
	return(new CTestGridApplication);
	}

GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}
