diff -r 000000000000 -r 2f259fa3e83a commonuisupport/grid/src/GRDIMG.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commonuisupport/grid/src/GRDIMG.CPP Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,2910 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// The member variables of the class CGridImg are as follows:- +// iGridRect - the coordinates of the rectangle containing the grid. +// iTitlePoint - The point at the top left of the grid not including the labels +// iMainPoint - The point at which the visible range starts (usually == iTitlePoint) +// iCursorPos - the cell reference of the current cursor position. +// iNewCursorPos - the proposed cell reference of the position that +// the cursor would occupy after a keypress. +// iAnchorPos - the cell reference of the position that the cursor must +// return to after a series of selected movements have been made. +// iGcPtr - a pointer to the current graphics context. +// iGc - the internal grid image Gc +// *iWin - a pointer to the current active window. +// *iGridLay, *iGridCellImg, *iGridLabelImg - allow access to the data in these +// other classes. +// *iSelected - allows access to the class that stores the array of selected ranges +// *iCursorMoveCallBack - a pointer to call back to an app after a cursor move +// iDragLabel - store the index of the label currently being dragged +// iCurrentDragPos - Stores the position of the label prior to it being dragged +// iDragDiff - Stores the distance between the second drag label and the pointer while a label drag is in progress +// iDragDim - Simply stores the dimension in which a label drag is in (X,Y or none) +// iDragBmp - Stores the bitmap of the dragged labels during a drag. +// iXRefPoint,iYRefPoint - Remembers which part of the grid the last pointer event was in. This is used in the +// SetCursorWithPointer() function logic. +// +// + +#include "GRDSTD.H" +#include "GRDPANIC.H" + +#if !defined(__WINC__) +#include +#endif + +const TInt KArrowLength = 11; +const TInt KArrowBreadth = 11; +const TInt KArrowSeparation = 11; + +GLDEF_C void Panic(TGridPanic aPanic) + { + _LIT(KGridPanic,"GRIDIMG"); + User::Panic(KGridPanic,aPanic); + } + +EXPORT_C void TGridUtils::FillRect(CGraphicsContext* aGc,TRgb aColor,const TRect &aRect) +/** Fills the specified rectangle with the specified colour. + +@param aGc The graphics context to be used. +@param aColor The colour which is to fill the rectangle. +@param aRect The rectangle to be filled. +@panic GRIDIMG 0 In debug mode only, if the pointer to the graphics context +is Null. */ + { + __ASSERT_DEBUG(aGc!=NULL,Panic(EGridImgInvalidGC)); + aGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + aGc->SetPenStyle(CGraphicsContext::ENullPen); + aGc->SetBrushColor(aColor); + aGc->DrawRect(aRect); + aGc->SetPenStyle(CGraphicsContext::ESolidPen); + aGc->SetBrushStyle(CGraphicsContext::ENullBrush); + } + +// + +EXPORT_C CGridCellImg::CGridCellImg() + : iBurstColOffset(0), + iBurstLeft(0), + iBurstRight(0), + iGridLineFlags(EIsHorizontalGridLines|EIsVerticalGridLines) +/** Default constructor. */ + { + } + +EXPORT_C CGridCellImg::~CGridCellImg() +/** Destructor. */ + { + } + + +EXPORT_C TInt CGridCellImg::DataWidthInPixelsL(const TCellRef& /*aCell*/) const +/** Gets the width of the data contained in the specified cell. +@publishedAll +@released +@param aCell The cell to be tested. +@return The width of the data, in pixels. The default implementation returns zero.*/ + { + return 0; + } + +EXPORT_C TBool CGridCellImg::DoesCellContainDataL(const TCellRef& /*aCell*/) const +/** Tests whether the specified cell contains data. +@publishedAll +@released +@param aCell The cell to be tested. +@return True, if the cell contains data; false, otherwise. The default implementation returns true.*/ + { + return ETrue; + } + +EXPORT_C void CGridCellImg::Reserved_1() + { +// No implementation yet + } + +void CGridCellImg::SetBurstingData(TInt aBurstColOffset,TInt aBurstLeft,TInt aBurstRight) + { + iBurstColOffset=aBurstColOffset; + iBurstLeft=aBurstLeft; + iBurstRight=aBurstRight; + } + +// + +EXPORT_C CGridLabelImg::CGridLabelImg(const TFontSpec& aFontSpec,MGraphicsDeviceMap* aGraphicsDeviceMap) + : iFontSpec(aFontSpec), + iGraphicsDeviceMap(aGraphicsDeviceMap) +/** Constructor taking specified parameters. + +@param aFontSpec A font specification in device independent terms. +@param aGraphicsDeviceMap An interface for mapping between twips and device-specific +units. */ + { + } + +EXPORT_C CGridLabelImg::~CGridLabelImg() +/** Destructor. + +Releases resources before the object is destroyed. Specifically, it releases +the font acquired when the object was constructed. */ + { + if (iGraphicsDeviceMap && iFont) + iGraphicsDeviceMap->ReleaseFont(iFont); + } + +EXPORT_C void CGridLabelImg::ConstructL() +/** Implements the second phase of two-phase construction. + +Specifically, it gets the nearest font to that specified in the font specification +passed to the constructor. */ + { + NotifyGraphicsDeviceMapChangeL(); + } + + +EXPORT_C void CGridLabelImg::DrawTopLeftLabelL(CGraphicsContext* aGc,const TRect& aRect) const +/** Fills the specified rectangle with a colour. + +The default implementation fills the specified rectangle with the background +colour value as defined by the grid colour specification in iGridColors. +@publishedAll +@released +@param aGc The graphics context to be used. +@param aRect The rectangle to be filled. +@see TGridColors */ + { +// TGridUtils::FillRect(aGc,KGridBackgroundColor,aRect); +//-> + TGridUtils::FillRect(aGc, iGridColors.iBackground, aRect); + } + +EXPORT_C void CGridLabelImg::DrawTopLeftLabelL(CGraphicsContext* aGc,const TRect& aRect, TRgb aColor) const +/** Fills the specified rectangle with the specified colour. + +@param aGc The graphics context to be used. +@param aRect The rectangle to be filled. +@param aColor The colour which is to fill the rectangle. */ + { + TGridUtils::FillRect(aGc, aColor, aRect); + } +//-> + + +EXPORT_C TInt CGridLabelImg::SideLabelWidthInPixels(TInt /*aStartRow*/,TInt /*aEndRow*/) const +/** Gets the width of the side labels. +@publishedAll +@released +@param aStartRow A start row. The default implementation does not use this value, +but a derived class can use this to define the start of a range of rows, +which may be useful if side labels have variable widths. +@param aEndRow An end row. The default implementation does not use this value, +but a derived class can use this to define the end of a range of rows, +which may be useful if side labels have variable widths. +@return The width value, in pixels. The default implementation returns the +pixel value corresponding to the twips value EDefaultSideLabelWidthInTwips, +as converted by the graphics device map function MGraphicsDeviceMap::HorizontalTwipsToPixels(). */ + { + __ASSERT_DEBUG(iGraphicsDeviceMap!=NULL,Panic(EGridNullGraphicsDeviceMap)); + return iGraphicsDeviceMap->HorizontalTwipsToPixels(EDefaultSideLabelWidthInTwips); + } + +EXPORT_C TInt CGridLabelImg::TopLabelHeightInPixels() const +/** Gets the height of the top labels. +@publishedAll +@released +@return The height value, in pixels. The default implementation returns the +pixel value corresponding to the twips value EDefaultTopLabelHeightInTwips, +as converted by the graphics device map function MGraphicsDeviceMap::VerticalTwipsToPixels(). */ + { + __ASSERT_DEBUG(iGraphicsDeviceMap!=NULL,Panic(EGridNullGraphicsDeviceMap)); + return iGraphicsDeviceMap->VerticalTwipsToPixels(EDefaultTopLabelHeightInTwips); + } + +EXPORT_C void CGridLabelImg::DrawRowCursorL(CGraphicsContext* /*aGc*/,const TRect& /*aRect*/) const +/** Draws a cursor to identify a row. + +The default implementation is empty. +@publishedAll +@released +@param aGc The graphics context to be used. +@param aRect The rectangle in which the cursor is to be drawn. */ +// +// To be overridden from if used +// + {} + +EXPORT_C void CGridLabelImg::ReleaseFont() +// +// Should be called before any change in the zoom factor device +/** Releases the font. + +This is called by the destructor, and should be called before calling SetGraphicsDeviceMap(). + +@see ConstructL() */ + { + __ASSERT_DEBUG(iGraphicsDeviceMap!=NULL,Panic(EGridNullGraphicsDeviceMap)); + iGraphicsDeviceMap->ReleaseFont(iFont); + iFont=NULL; + } + +EXPORT_C void CGridLabelImg::NotifyGraphicsDeviceMapChangeL() +/** Deals with the result of changing the graphics device map, i.e. the interface +for mapping between twips and device-specific units. + +The function releases the existing font, and then tries to get the nearest +font to that specified in the font specification. + +@see ConstructL() +@see SetGraphicsDeviceMap() */ + { + ReleaseFont(); + User::LeaveIfError(iGraphicsDeviceMap->GetNearestFontInTwips(iFont,iFontSpec)); + } + +// + +EXPORT_C CGridImg* CGridImg::NewL(CGridCellImg* aGridCellImg,CGridLay* aGridLay) +/** Creates a new grid image object suitable for printing. + +@param aGridCellImg A pointer to an object that draws the contents of a +single cell. +@param aGridLay A pointer to the object that controls the layout of rows and +columns. +@return A pointer to the new grid image object. */ + { +//-> + CGridImg* self = new(ELeave) CGridImg(aGridCellImg,aGridLay); + if (aGridLay && aGridCellImg) + aGridCellImg->SetGridColors(aGridLay->GridColors()); + return self; +//-> +// return new(ELeave) CGridImg(aGridCellImg,aGridLay); + } + +CGridImg::CGridImg(CGridCellImg* aGridCellImg,CGridLay* aGridLay) +// +// Construct a partial gridImg object for printing with the same data as the passed gridImg +// and a handle to the passed gridLay + : iGridCellImg(aGridCellImg), + iGridLay(aGridLay) + { + } + +EXPORT_C CGridImg* CGridImg::NewL(CGraphicsDevice* aGraphicsDevice,CGridCellImg* aGridCellImg,CGridLay* aGridLay) +/** Creates a new grid image object. + +@param aGraphicsDevice The graphics device to be used for drawing. +@param aGridCellImg A pointer to an object that draws the contents of a single +cell. +@param aGridLay A pointer to the object that controls the layout of rows and +columns. +@return A pointer to the new grid image object. */ + { + CGridImg* self=new(ELeave) CGridImg(aGraphicsDevice,aGridCellImg,aGridLay); + CleanupStack::PushL(self); +//-> + if (aGridLay && aGridCellImg) + aGridCellImg->SetGridColors(aGridLay->GridColors()); +//-> + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CGridImg::CGridImg(CGraphicsDevice *aGraphicsDevice,CGridCellImg *aGridCellImg,CGridLay* aGridLay) + : iGraphicsDevice(aGraphicsDevice), + iGridCellImg(aGridCellImg), + iGridLay(aGridLay), + iDragLabel(0), + iCurrentDragPos(0), + iDragDiff(0), + iDragFlags(0), + iDragDim(ENoDrag), + iXRefPoint(EMainRef), + iYRefPoint(EMainRef) + { + } + +void CGridImg::ConstructL() + { +#if !defined(__WINC__) + if (iGraphicsDevice) + User::LeaveIfError(iGraphicsDevice->CreateContext((CGraphicsContext*&)iGc)); +#endif + } + +EXPORT_C CGridImg::~CGridImg() +/** Destructor. + +Frees resources before destruction of the object. */ + { +#if !defined(__WINC__) + delete iGc; + delete iDragBmp; +#endif + delete iSelected; + } + +void CGridImg::ConstructSelectedL(const TRangeRef& aGridRange) + { + delete iSelected; + iSelected=NULL; // in case next line fails + iSelected = CGridCellRegion::NewL(aGridRange); + } + +void CGridImg::CreateGc(CGraphicsContext* aGc) + { + __ASSERT_DEBUG(iGcPtr==NULL,Panic(EGridImgInvalidGC)); + iGcPtr=aGc; +#if !defined(__WINC__) + if (iGcPtr==iGc) + iGc->Activate(*iWin); +#endif + } + +void CGridImg::DeleteGc() + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); +#if !defined(__WINC__) + if (iGcPtr==iGc) + iGc->Deactivate(); +#endif + iGcPtr=NULL; + } + +void CGridImg::DrawAllGridLabelsL() const +// Draw all the grid labels + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + DrawTopLeftGridLabelL(); + TRangeRef titleRange=iGridLay->TitleRange(); + if (iGridLay->IsHorizontalTitleLine()) + DrawSideGridLabelsL(titleRange.iFrom.iRow,titleRange.iTo.iRow-1,ETitleRef); + if (iGridLay->IsVerticalTitleLine()) + DrawTopGridLabelsL(titleRange.iFrom.iCol,titleRange.iTo.iCol-1,ETitleRef); + TRangeRef visRange=iGridLay->VisibleRange(); + DrawTopGridLabelsL(visRange.iFrom.iCol,visRange.iTo.iCol); + DrawSideGridLabelsL(visRange.iFrom.iRow,visRange.iTo.iRow); + } + +void CGridImg::DrawTopLeftGridLabelL() const +// Draw top left corner label + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + if (iGridLay->IsTopLabels() && iGridLay->IsSideLabels()) + { + TRect rect(iGridRect.iTl,iTitlePoint); + if (iGridLay->IsGridLabelSeparators()) + { + rect.Resize(-1,-1); +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + TPoint start(rect.iTl.iX,rect.iBr.iY); + TPoint finish(rect.iBr.iX+1,rect.iBr.iY); + iGcPtr->DrawLine(start,finish); + start.SetXY(rect.iBr.iX,rect.iTl.iY); + iGcPtr->DrawLine(start,rect.iBr); + } +//-> +// iGridLabelImg->DrawTopLeftLabelL(iGcPtr,rect); + iGridLabelImg->DrawTopLeftLabelL(iGcPtr, rect, iGridLay->GridColors().iBackground); +//-> + } + } + +void CGridImg::DrawTopGridLabelsL(TInt aStartCol,TInt aEndCol,TRefPoint aXRef) const +// Draws all the top grid labels within the specified column range + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + if (!iGridLay->IsTopLabels() || iGridLabelImg==NULL) + return; + TInt separatorCorr=(iGridLay->IsGridLabelSeparators()) ? 1 : 0; + TRect rect; + rect.iTl.iY=iGridRect.iTl.iY; + rect.iBr.iY=iTitlePoint.iY-separatorCorr; + rect.iTl.iX=((aXRef==ETitleRef) ? iGridLay->TitleColumnToXVal(aStartCol) : + iGridLay->ColumnToXVal(aStartCol)); + rect.iBr.iX=rect.iTl.iX-separatorCorr; + TBool doGrayFill=EFalse; + TRangeRef visRange=iGridLay->VisibleRange(); + if (aEndCol>=visRange.iTo.iCol) + { + aEndCol=visRange.iTo.iCol; + if (aEndCol>iGridLay->GridRange().iTo.iCol) + { + aEndCol--; + doGrayFill=ETrue; + } + } + iGcPtr->SetClippingRect(TRect(iTitlePoint.iX,iGridRect.iTl.iY,iGridRect.iBr.iX,iTitlePoint.iY)); + if (iGridLay->IsGridLabelSeparators()) + { + for (TInt ii=aStartCol;ii<=aEndCol;ii++) + { + rect.iBr.iX+=iGridLay->ColumnWidthInPixels(ii); + iGridLabelImg->DrawColLabelL(iGcPtr,ii,rect); + rect.iTl.iX=rect.iBr.iX; +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + iGcPtr->DrawLine(rect.iTl,rect.iBr); + rect.iTl.iX++; + } + } + else + { + for (TInt ii=aStartCol;ii<=aEndCol;ii++) + { + rect.iBr.iX+=iGridLay->ColumnWidthInPixels(ii); + iGridLabelImg->DrawColLabelL(iGcPtr,ii,rect); + rect.iTl.iX=rect.iBr.iX; + } + } + if (doGrayFill) + { + TGridUtils::FillRect(iGcPtr,iGridLay->iGridEdgeColor, + TRect(rect.iTl.iX,rect.iTl.iY,iGridRect.iBr.iX,rect.iBr.iY+separatorCorr)); + } + if (iGridLay->IsGridLabelSeparators()) + { + rect.iBr.iX++; +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); + iGcPtr->DrawLine(TPoint(iTitlePoint.iX,rect.iBr.iY),rect.iBr); +//-> + } + iGcPtr->CancelClippingRect(); + } + +void CGridImg::DrawSideGridLabelsL(TInt aStartRow,TInt aEndRow,TRefPoint aYRef) const + { + // + // Draw all the side grid labels within the specified row range + // + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + if (!iGridLay->IsSideLabels() || iGridLabelImg==NULL) + return; + TInt separatorCorr=(iGridLay->IsGridLabelSeparators()) ? 1 : 0; + TRect rect; + rect.iTl.iX=iGridRect.iTl.iX; + rect.iBr.iX=iTitlePoint.iX-separatorCorr; + rect.iTl.iY=((aYRef==ETitleRef) ? iGridLay->TitleRowToYVal(aStartRow) : + iGridLay->RowToYVal(aStartRow)); + TInt startY=rect.iTl.iY; + rect.iBr.iY=rect.iTl.iY-separatorCorr; + TBool doGrayFill=EFalse; + TRangeRef visRange=iGridLay->VisibleRange(); + if (aEndRow>=visRange.iTo.iRow) + { + aEndRow=visRange.iTo.iRow; + TInt reqRow; + if (iGridLay->RequestRow(aEndRow,reqRow)) + { + if (aEndRow!=reqRow) + { + aEndRow--; + doGrayFill=ETrue; + } + } + else + { + aEndRow=aStartRow-1; // guarantees not to go into loop + doGrayFill=ETrue; + } + } + iGcPtr->SetClippingRect(TRect(iGridRect.iTl.iX,iTitlePoint.iY,iTitlePoint.iX,iGridRect.iBr.iY)); + if (iGridLay->IsGridLabelSeparators()) + { + for (TInt ii=aStartRow;ii<=aEndRow;ii++) + { + rect.iBr.iY+=iGridLay->RowHeightInPixels(ii); + iGridLabelImg->DrawRowLabelL(iGcPtr,ii,rect); + if (ii==iCursorPos.iRow) + iGridLabelImg->DrawRowCursorL(iGcPtr,rect); + rect.iTl.iY=rect.iBr.iY; +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + iGcPtr->DrawLine(rect.iTl,rect.iBr); + rect.iTl.iY++; + } + } + else + { + for (TInt ii=aStartRow;ii<=aEndRow;ii++) + { + rect.iBr.iY+=iGridLay->RowHeightInPixels(ii); + iGridLabelImg->DrawRowLabelL(iGcPtr,ii,rect); + if (ii==iCursorPos.iRow) + iGridLabelImg->DrawRowCursorL(iGcPtr,rect); + rect.iTl.iY=rect.iBr.iY; + } + } + if (doGrayFill) + { + TGridUtils::FillRect(iGcPtr,iGridLay->iGridEdgeColor, + TRect(rect.iTl.iX,rect.iTl.iY,rect.iBr.iX+separatorCorr,iGridRect.iBr.iY)); + } + if (iGridLay->IsGridLabelSeparators()) + { + rect.iBr.iY++; +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + iGcPtr->DrawLine(TPoint(rect.iBr.iX,startY),rect.iBr); + } + iGcPtr->CancelClippingRect(); + } + +void CGridImg::DrawSideGridLabelIfOnScreenL(TInt aRow) const + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + TBool doDraw=EFalse; + TRefPoint refPoint=EMainRef; + TRangeRef visRange=iGridLay->VisibleRange(); + if (aRow>=visRange.iFrom.iRow && aRow<=visRange.iTo.iRow) + doDraw=ETrue; + else if (iGridLay->IsHorizontalTitleLine()) + { + TRangeRef titleRange=iGridLay->TitleRange(); + if (aRow>=titleRange.iFrom.iRow && aRowCreateGc(iGc); + DrawVerticalTitleLine(); + DrawHorizontalTitleLine(); + ((CGridImg*)this)->DeleteGc(); +#endif + } + +EXPORT_C void CGridImg::ClearTitleLineRegionL(const TPoint& aCrossPoint) const +/** Clears the region where the the title lines are. + +@param aCrossPoint Any point within the title region. */ + { + TRect rect(Max(aCrossPoint.iX-1,iTitlePoint.iX),iTitlePoint.iY, + aCrossPoint.iX,iGridRect.iBr.iY); + BeginRedrawAndDrawL(rect); + rect.SetRect(iTitlePoint.iX,Max(aCrossPoint.iY-1,iTitlePoint.iY), + iGridRect.iBr.iX,aCrossPoint.iY); + BeginRedrawAndDrawL(rect); + } + +void CGridImg::DrawVerticalTitleLine() const + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + if (iMainPoint.iX>iTitlePoint.iX) + { +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + iGcPtr->DrawLine(TPoint(iMainPoint.iX-1,iTitlePoint.iY-1), + TPoint(iMainPoint.iX-1,iGridRect.iBr.iY)); + } + } + +void CGridImg::DrawHorizontalTitleLine() const + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + if (iMainPoint.iY>iTitlePoint.iY) + { +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + iGcPtr->DrawLine(TPoint(iTitlePoint.iX-1,iMainPoint.iY-1), + TPoint(iGridRect.iBr.iX,iMainPoint.iY-1)); + } + } + +void CGridImg::DrawAllGridLinesAndCellsL() const + // Draws all the grid lines and cells + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + TRangeRef visRange=iGridLay->VisibleRange(); + if (iGridLay->IsEncroachingCellBorders()) + { + if (iGridLay->IsVisibleToRowFullyVisible()) + visRange.iTo.iRow++; + if (iGridLay->IsVisibleToColumnFullyVisible()) + visRange.iTo.iCol++; + } + TRect clippingRect; + TRangeRef titleRange=iGridLay->TitleRange(); + TBool isHorizontalTitleLine=iGridLay->IsHorizontalTitleLine(); + TBool isVerticalTitleLine=iGridLay->IsVerticalTitleLine(); + TRangeRef range; + if (isHorizontalTitleLine && isVerticalTitleLine) + { + clippingRect.SetRect(iTitlePoint,iMainPoint); + DrawGridLinesAndCellsInRangeL(titleRange,clippingRect,ETitleRef,ETitleRef); + } + if (isHorizontalTitleLine) + { + clippingRect.SetRect(iMainPoint.iX,iTitlePoint.iY,iGridRect.iBr.iX,iMainPoint.iY); + range.SetRange(titleRange.iFrom.iRow,visRange.iFrom.iCol, + titleRange.iTo.iRow,visRange.iTo.iCol); + DrawGridLinesAndCellsInRangeL(range,clippingRect,EMainRef,ETitleRef); + } + if (isVerticalTitleLine) + { + clippingRect.SetRect(iTitlePoint.iX,iMainPoint.iY,iMainPoint.iX,iGridRect.iBr.iY); + range.SetRange(visRange.iFrom.iRow,titleRange.iFrom.iCol, + visRange.iTo.iRow,titleRange.iTo.iCol); + DrawGridLinesAndCellsInRangeL(range,clippingRect,ETitleRef,EMainRef); + } + clippingRect.SetRect(iMainPoint,iGridRect.iBr); + DrawGridLinesAndCellsInRangeL(visRange,clippingRect); + } + +void CGridImg::DrawGridLinesAndCellsInRangeL(const TRangeRef& aRange,const TRect& aClipRect, + TRefPoint aXRef,TRefPoint aYRef) const +// Draws the grid cells for the given cell range + { + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + TRect rangeRect; + if (aYRef==ETitleRef) + { + rangeRect.iTl.iY=iGridLay->TitleRowToYVal(aRange.iFrom.iRow); + rangeRect.iBr.iY=iMainPoint.iY-1; + } + else + { + rangeRect.iTl.iY=iGridLay->RowToYVal(aRange.iFrom.iRow); + rangeRect.iBr.iY=iGridRect.iBr.iY; + } + if (aXRef==ETitleRef) + { + rangeRect.iTl.iX=iGridLay->TitleColumnToXVal(aRange.iFrom.iCol); + rangeRect.iBr.iX=iMainPoint.iX-1; + } + else + { + rangeRect.iTl.iX=iGridLay->ColumnToXVal(aRange.iFrom.iCol); + rangeRect.iBr.iX=iGridRect.iBr.iX; + } + + TInt endCol=aRange.iTo.iCol; + TBool doRightFill=EFalse; + TRangeRef visRange=iGridLay->VisibleRange(); + if (endCol>=visRange.iTo.iCol) + { + endCol=visRange.iTo.iCol; + if (endCol>iGridLay->GridRange().iTo.iCol) + { + endCol--; + doRightFill=ETrue; + } + } + TInt endRow=aRange.iTo.iRow; + TBool doBottomFill=EFalse; + if (endRow>=visRange.iTo.iRow) + { + endRow=visRange.iTo.iRow; + TInt reqRow; + if (iGridLay->RequestRow(endRow,reqRow)) + { + if (endRow!=reqRow) + { + endRow--; + doBottomFill=ETrue; + } + } + else + { + endRow=aRange.iFrom.iRow-1; + doBottomFill=ETrue; + } + } +//-> + iGcPtr->SetPenColor((iGcPtr->Device()->DisplayMode()==EGray2) ? KRgbBlack : iGridLay->GridColors().iLines); // To workaround a problem when printing gray lines +// iGcPtr->SetPenColor((iGcPtr->Device()->DisplayMode()==EGray2) ? KRgbBlack : KRgbGridLines); // To workaround a problem when printing gray lines +//-> + TRect rect; + rect.iTl.iX=rect.iBr.iX=rangeRect.iTl.iX-1; + if (iGridLay->IsVerticalGridLines()) + { + rect.iTl.iY=rangeRect.iTl.iY; + rect.iBr.iY=(doBottomFill) ? iGridLay->RowToYVal(endRow+1) : rangeRect.iBr.iY; + } + TInt startCol=aRange.iFrom.iCol; + TInt pageCol=KMaxTInt; + if (!iGridLay->IsPageBreakLinesHidden()) + iGridLay->FindNextColumnPageBreak(startCol,pageCol); + iGcPtr->SetClippingRect(aClipRect); + for (;startCol<=endCol;startCol++) + { + rect.Move(iGridLay->ColumnWidthInPixels(startCol),0); + if (startCol==pageCol) + { + TPoint start(rect.iTl.iX,iTitlePoint.iY); + TPoint end(rect.iBr.iX,rangeRect.iBr.iY); +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iBackground); +// iGcPtr->SetPenColor(KRgbGridBackground); +//-> + iGcPtr->DrawLine(start,end); +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + iGcPtr->SetPenStyle((iGridLay->IsHardColumnPageBreak(pageCol+1)) + ? CGraphicsContext::EDotDashPen : CGraphicsContext::EDashedPen); + iGcPtr->DrawLine(start,end); + iGcPtr->SetPenStyle(CGraphicsContext::ESolidPen); +//-> + iGcPtr->SetPenColor((iGcPtr->Device()->DisplayMode()==EGray2) ? KRgbBlack : iGridLay->GridColors().iLines); +// iGcPtr->SetPenColor((iGcPtr->Device()->DisplayMode()==EGray2) ? KRgbBlack : KRgbGridLines); +//-> + iGridLay->FindNextColumnPageBreak(startCol+1,pageCol); + } + else + iGcPtr->DrawLine(rect.iTl,rect.iBr); + } + if (doRightFill) + { + TGridUtils::FillRect(iGcPtr,iGridLay->iGridEdgeColor, + TRect(rect.iTl.iX+1,rangeRect.iTl.iY,iGridRect.iBr.iX,rangeRect.iBr.iY)); + } + + rect.iTl.iY=rect.iBr.iY=rangeRect.iTl.iY-1; + if (iGridLay->IsHorizontalGridLines()) + { + rect.iTl.iX=rangeRect.iTl.iX; + rect.iBr.iX=(doRightFill) ? iGridLay->ColumnToXVal(endCol+1) : rangeRect.iBr.iX; + } + TInt startRow=aRange.iFrom.iRow; + TInt pageRow=KMaxTInt; + if (!iGridLay->IsPageBreakLinesHidden()) + iGridLay->FindNextRowPageBreak(startRow,pageRow); + for (;startRow<=endRow;startRow++) + { + rect.Move(0,iGridLay->RowHeightInPixels(startRow)); + if (startRow==pageRow) + { + TPoint start(iTitlePoint.iX,rect.iTl.iY); + TPoint end(rangeRect.iBr.iX,rect.iBr.iY); +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iBackground); +// iGcPtr->SetPenColor(KRgbGridBackground); +//-> + iGcPtr->DrawLine(start,end); +//-> + iGcPtr->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// iGcPtr->SetPenColor(KRgbGridLabelSeparators); +//-> + iGcPtr->SetPenStyle((iGridLay->IsHardRowPageBreak(pageRow+1)) + ? CGraphicsContext::EDotDashPen : CGraphicsContext::EDashedPen); + iGcPtr->DrawLine(start,end); + iGcPtr->SetPenStyle(CGraphicsContext::ESolidPen); +//-> + iGcPtr->SetPenColor((iGcPtr->Device()->DisplayMode()==EGray2) ? KRgbBlack : iGridLay->GridColors().iLines); +// iGcPtr->SetPenColor((iGcPtr->Device()->DisplayMode()==EGray2) ? KRgbBlack : KRgbGridLines); +//-> + iGridLay->FindNextRowPageBreak(startRow+1,pageRow); + } + else + iGcPtr->DrawLine(rect.iTl,rect.iBr); + } + if (doBottomFill) + { + TGridUtils::FillRect(iGcPtr,iGridLay->iGridEdgeColor, + TRect(rangeRect.iTl.iX,rect.iTl.iY+1,rangeRect.iBr.iX,iGridRect.iBr.iY)); + } + iGcPtr->CancelClippingRect(); + DrawCellsToGcL(iGcPtr,aRange,aClipRect,rangeRect.iTl); + } + +void CGridImg::DrawCellsToGcL(CGraphicsContext* aGc,const TRangeRef& aRange,const TRect& aClipRect, + const TPoint& aStartPoint,TInt aScaleFactor) const + { + TCellRef startCell=aRange.iFrom; + if (!iGridLay->LimitCell(startCell)) + return; // Nothing to draw + TCellRef endCell = aRange.iTo; + iGridLay->LimitCell(endCell); + TRect rect; + TInt yPos=aStartPoint.iY; + rect.iTl.iY = yPos*EScaleOneToOne/aScaleFactor; + TCellRef cell = aRange.iFrom; + TInt horzLineCorr=(iGridLay->IsHorizontalGridLines()) ? 1 : 0; + TInt vertLineCorr=(iGridLay->IsVerticalGridLines()) ? 1 : 0; + iGridCellImg->iGridLineFlags=0; + if (horzLineCorr) + iGridCellImg->iGridLineFlags|=CGridCellImg::EIsHorizontalGridLines; + if (vertLineCorr) + iGridCellImg->iGridLineFlags|=CGridCellImg::EIsVerticalGridLines; + for (;cell.iRow<=endCell.iRow;cell.iRow++) + { + TInt xPos=aStartPoint.iX; + rect.iTl.iX=xPos*EScaleOneToOne/aScaleFactor; + yPos+=iGridLay->RowHeightInPixels(cell.iRow); + rect.iBr.iY = yPos*EScaleOneToOne/aScaleFactor-vertLineCorr; + cell.iCol=aRange.iFrom.iCol; + if (iGridLay->IsColumnBursting()) + { + if (cell.iCol<=endCell.iCol) + { + xPos+=iGridLay->ColumnWidthInPixels(cell.iCol); + rect.iBr.iX = xPos*EScaleOneToOne/aScaleFactor-horzLineCorr; + TCellRef burstCell=cell; + TInt burstLeft=CalcBurstLeftL(burstCell,aScaleFactor); + DrawBurstingCellL(aGc,cell,rect,aClipRect,aScaleFactor,burstLeft,burstCell); + burstLeft+=rect.Width()+horzLineCorr; + rect.iTl.iX=rect.iBr.iX+horzLineCorr; + for (cell.iCol++;cell.iCol<=endCell.iCol;cell.iCol++) + { + xPos+=iGridLay->ColumnWidthInPixels(cell.iCol); + rect.iBr.iX = xPos*EScaleOneToOne/aScaleFactor-horzLineCorr; + if (iGridCellImg->DoesCellContainDataL(cell)) + { + burstLeft=0; + burstCell.iCol=cell.iCol; + } + DrawBurstingCellL(aGc,cell,rect,aClipRect,aScaleFactor,burstLeft,burstCell); + burstLeft+=rect.Width()+horzLineCorr; + rect.iTl.iX=rect.iBr.iX+horzLineCorr; + } + } + } + else + { + for (;cell.iCol<=endCell.iCol;cell.iCol++) + { + xPos+=iGridLay->ColumnWidthInPixels(cell.iCol); + rect.iBr.iX = xPos*EScaleOneToOne/aScaleFactor-horzLineCorr; + iGridCellImg->DrawL(aGc,cell,rect,aClipRect); + rect.iTl.iX=rect.iBr.iX+horzLineCorr; + } + } + rect.iTl.iY=rect.iBr.iY+vertLineCorr; + } + ResetGcToDefault(aGc); + } + +void CGridImg::DrawBurstingCellL(CGraphicsContext* aGc,const TCellRef& aCell,const TRect& aRect,const TRect& aClipRect, + TInt aScaleFactor,TInt aBurstLeft,const TCellRef& aBurstCell) const + { + TInt burstDataWidth=iGridCellImg->DataWidthInPixelsL(aBurstCell); + if (burstDataWidth<=aBurstLeft) + iGridCellImg->DrawL(aGc,aCell,aRect,aClipRect); + else + { + TInt excessRight=burstDataWidth-aBurstLeft-aRect.Width(); + iGridCellImg->SetBurstingData(aCell.iCol-aBurstCell.iCol,aBurstLeft, + CalcBurstRightL(aCell,excessRight,aScaleFactor)); + iGridCellImg->DrawL(aGc,aCell,aRect,aClipRect); + iGridCellImg->SetBurstingData(); + } + } + +TInt CGridImg::CalcBurstLeftL(TCellRef& aBurstCell,TInt aScaleFactor) const + { + enum { EMaxNumberChecked = 20 }; + const TInt limit=Max(aBurstCell.iCol-EMaxNumberChecked,iGridLay->GridRange().iFrom.iCol); + TInt burstLeft=0; + while (aBurstCell.iCol>limit && !iGridCellImg->DoesCellContainDataL(aBurstCell)) + { + burstLeft+=iGridLay->ColumnWidthInPixels(--aBurstCell.iCol); + } + return burstLeft*EScaleOneToOne/aScaleFactor; + } + +TInt CGridImg::CalcBurstRightL(const TCellRef& aCell,TInt aExcessRight,TInt aScaleFactor) const + { + TInt limit=iGridLay->GridRange().iTo.iCol; + TInt burstRight=0; + TInt scaledBurstRight=0; + for (TCellRef forwardCell(aCell.iRow,aCell.iCol+1);forwardCell.iCol<=limit;forwardCell.iCol++) + { + TInt width=iGridLay->ColumnWidthInPixels(forwardCell.iCol); + if (iGridCellImg->DoesCellContainDataL(forwardCell) || scaledBurstRight>aExcessRight) + { + break; + } + burstRight+=width; + scaledBurstRight=burstRight*EScaleOneToOne/aScaleFactor; + } + return scaledBurstRight; + } + +EXPORT_C void CGridImg::DrawCellL(const TCellRef &aCell) const +/** Draws the content of the specified cell. + +@param aCell The cell to be drawn. */ + { + TRect rect=PartialCellRectL(aCell,MainRect()); + TRect clipRect; + TBool isHorizontalTitleLine=iGridLay->IsHorizontalTitleLine(); + TBool isVerticalTitleLine=iGridLay->IsVerticalTitleLine(); + if (isHorizontalTitleLine && isVerticalTitleLine) + { + clipRect.SetRect(iTitlePoint,iMainPoint); + rect.BoundingRect(PartialCellRectL(aCell,clipRect,ETitleRef,ETitleRef)); + } + if (isHorizontalTitleLine) + { + clipRect.SetRect(iMainPoint.iX,iTitlePoint.iY,iGridRect.iBr.iX,iMainPoint.iY); + rect.BoundingRect(PartialCellRectL(aCell,clipRect,EMainRef,ETitleRef)); + } + if (isVerticalTitleLine) + { + clipRect.SetRect(iTitlePoint.iX,iMainPoint.iY,iMainPoint.iX,iGridRect.iBr.iY); + rect.BoundingRect(PartialCellRectL(aCell,clipRect,ETitleRef,EMainRef)); + } + BeginRedrawAndDrawL(rect); + } + +TRect CGridImg::PartialCellRectL(const TCellRef& aCell,const TRect& aClipRect, + TRefPoint aXRef,TRefPoint aYRef) const + { + TRect rect; + rect.iTl=RelativeCellToPoint(aCell,aXRef,aYRef); + rect.iBr=rect.iTl+iGridLay->CellToPoint(aCell,aCell+TCellRef(1,1)); + if (iGridLay->IsColumnBursting()) + { + TInt limit=iGridLay->GridRange().iTo.iCol; + for (TCellRef forwardCell(aCell.iRow,aCell.iCol+1);rect.iBr.iXDoesCellContainDataL(forwardCell)) + break; + rect.iBr.iX+=iGridLay->ColumnWidthInPixels(forwardCell.iCol); + } + } + rect.iTl-=TPoint(2,2); //For cell borders + rect.Intersection(aClipRect); + return rect; + } + +EXPORT_C void CGridImg::DrawRangeL(const TRangeRef& aRange) const +/** Draws the rectangle corresponding to the specified range. + +@param aRange The range to be drawn. */ + { + TRect rect=PartialRangeRect(aRange,MainRect()); + TRect clipRect; + TBool isHorizontalTitleLine=iGridLay->IsHorizontalTitleLine(); + TBool isVerticalTitleLine=iGridLay->IsVerticalTitleLine(); + if (isHorizontalTitleLine && isVerticalTitleLine) + { + clipRect.SetRect(iTitlePoint,iMainPoint); + rect.BoundingRect(PartialRangeRect(aRange,clipRect,ETitleRef,ETitleRef)); + } + if (isHorizontalTitleLine) + { + clipRect.SetRect(iMainPoint.iX,iTitlePoint.iY,iGridRect.iBr.iX,iMainPoint.iY); + rect.BoundingRect(PartialRangeRect(aRange,clipRect,EMainRef,ETitleRef)); + } + if (isVerticalTitleLine) + { + clipRect.SetRect(iTitlePoint.iX,iMainPoint.iY,iMainPoint.iX,iGridRect.iBr.iY); + rect.BoundingRect(PartialRangeRect(aRange,clipRect,ETitleRef,EMainRef)); + } + BeginRedrawAndDrawL(rect); + } + +TRect CGridImg::PartialRangeRect(const TRangeRef& aRange,const TRect& aClipRect, + TRefPoint aXRef,TRefPoint aYRef) const + { + TRect rect; + rect.iTl=RelativeCellToPoint(aRange.iFrom,aXRef,aYRef); + rect.iBr=rect.iTl+iGridLay->CellToPoint(aRange.iFrom,aRange.iTo+TCellRef(1,1)); + if (iGridLay->IsColumnBursting()) + rect.iBr.iX=iGridRect.iBr.iX; + rect.iTl-=TPoint(2,2); //For cell borders + rect.Intersection(aClipRect); + return rect; + } + +EXPORT_C void CGridImg::DrawSelectedL() const +/** Draws the currently selected region. */ + { + TInt count=iSelected->Count(); + if (count==0) + DrawCellL(iCursorPos); + else if (count==1) + DrawRangeL((*iSelected)[0]); + else + BeginRedrawAndDrawL(); + } + +#if defined(__WINC__) +void CGridImg::HighlightMinRegionL(const TRegion& /*aOldRegion*/,const TRegion& /*aNewRegion*/) + {} +#else + +void CGridImg::HighlightMinRegionL(const TRegion& aOldRegion,const TRegion& aNewRegion) +// +// Highlights the minimum necessary region to get from the old to the new region +// + { + RRegion unionRegion; + unionRegion.Copy(aOldRegion); + unionRegion.Union(aNewRegion); + RRegion tempRegion; + tempRegion.Copy(aOldRegion); + tempRegion.Intersect(aNewRegion); + unionRegion.SubRegion(tempRegion); + tempRegion.Close(); + unionRegion.Tidy(); + if (unionRegion.CheckError()) + { + unionRegion.Close(); + User::Leave(KErrNoMemory); + } + CreateGc(iGc); + HighlightRegion(unionRegion); + DeleteGc(); + unionRegion.Close(); + } +#endif + +void CGridImg::HighlightRegion(const TRegion &aRegion) const + { + // + // Fills each of the rectangles in the passed region one by one + // + __ASSERT_DEBUG(iGcPtr!=NULL,Panic(EGridImgInvalidGC)); + TInt count=aRegion.Count(); + if (count) + { + iGcPtr->SetDrawMode(CGraphicsContext::EDrawModeNOTSCREEN); + iGcPtr->SetBrushStyle(CGraphicsContext::ESolidBrush); + for (TInt ii=0;iiDrawRect(aRegion[ii]); + iGcPtr->SetBrushStyle(CGraphicsContext::ENullBrush); + iGcPtr->SetDrawMode(CGraphicsContext::EDrawModePEN); + } + } + +TPoint CGridImg::RelativeCellToPoint(const TCellRef& aCell, + TRefPoint aXRef,TRefPoint aYRef) const + { + TPoint ret; + ret.iX=(aXRef==ETitleRef) ? iGridLay->TitleColumnToXVal(aCell.iCol) : + iGridLay->ColumnToXVal(aCell.iCol); + ret.iY=(aYRef==ETitleRef) ? iGridLay->TitleRowToYVal(aCell.iRow) : + iGridLay->RowToYVal(aCell.iRow); + return ret; + } + +TCellRef CGridImg::RelativePointToCell(const TPoint& aPoint, + TRefPoint aXRef,TRefPoint aYRef) const + { + TCellRef ret; + ret.iCol=(aXRef==ETitleRef) ? iGridLay->XValToTitleColumn(aPoint.iX) : + iGridLay->XValToColumn(aPoint.iX); + ret.iRow=(aYRef==ETitleRef) ? iGridLay->YValToTitleRow(aPoint.iY) : + iGridLay->YValToRow(aPoint.iY); + return ret; + } + +void CGridImg::AppendPartialHighlightRegionL(TRegion& aRegion,const TRect& aClipRect, + TRefPoint aXRef,TRefPoint aYRef) const +// +// returns ETrue if there's an error in the region manipulation + { + TInt count=iSelected->Count(); + if (!count) + { + if (iGridLay->IsCursorVisible()) + { + if (iGridLay->IsCellOutOfGridRange(iCursorPos)) + return; + TRect cursor(RelativeCellToPoint(iCursorPos,aXRef,aYRef),TSize(0,0)); + cursor.iBr.iX+=iGridLay->ColumnWidthInPixels(iCursorPos.iCol); + cursor.iBr.iY+=iGridLay->RowHeightInPixels(iCursorPos.iRow); + + TRegionFix<4> region; + region.AddRect(TRect(cursor.iTl.iX-2,cursor.iTl.iY-2,cursor.iBr.iX+1,cursor.iTl.iY+1)); + region.AddRect(TRect(cursor.iTl.iX-2,cursor.iBr.iY-2,cursor.iBr.iX+1,cursor.iBr.iY+1)); + region.AddRect(TRect(cursor.iTl.iX-2,cursor.iTl.iY+1,cursor.iTl.iX+1,cursor.iBr.iY-2)); + region.AddRect(TRect(cursor.iBr.iX-2,cursor.iTl.iY+1,cursor.iBr.iX+1,cursor.iBr.iY-2)); + region.ClipRect(aClipRect); + aRegion.Union(region); + } + } + else if (iGridLay->IsHighlightVisible()) + { + for (TInt ii=0;iiLimitCell(range.iFrom)) + continue; + iGridLay->LimitCell(range.iTo); + TRect rect; + rect.iTl=RelativeCellToPoint(range.iFrom,aXRef,aYRef); + rect.iBr=RelativeCellToPoint(range.iTo+TCellRef(1,1),aXRef,aYRef); + rect.Resize(-1,-1); + rect.Shrink(1,1); + rect.Intersection(aClipRect); + if (iSelected->IsColSelected(range.iFrom.iCol,ii) && + (iTitlePoint.iY==iMainPoint.iY || aYRef==ETitleRef) && + !iGridLay->IsColumnSelectionDisabled()) + { + rect.iTl.iY=Min(rect.iTl.iY,iGridRect.iTl.iY+1); + } + if (iSelected->IsRowSelected(range.iFrom.iRow,ii) && + (iTitlePoint.iX==iMainPoint.iX || aXRef==ETitleRef) && + !iGridLay->IsRowSelectionDisabled()) + { + rect.iTl.iX=Min(rect.iTl.iX,iGridRect.iTl.iX+1); + } + aRegion.AddRect(rect); + } + if (iGridLay->IsCursorVisible()) + { + if (!iGridLay->IsCellOutOfGridRange(iAnchorPos)) + { + TRect anchorRect=(TRect(RelativeCellToPoint(iAnchorPos,aXRef,aYRef),TSize(0,0))); + anchorRect.iBr.iX+=iGridLay->ColumnWidthInPixels(iAnchorPos.iCol); + anchorRect.iBr.iY+=iGridLay->RowHeightInPixels(iAnchorPos.iRow); + anchorRect.Resize(-1,-1); + anchorRect.Shrink(2,2); + anchorRect.Intersection(aClipRect); + aRegion.SubRect(anchorRect); + } + } + } + if (aRegion.CheckError()) + User::Leave(KErrNoMemory); + } + +void CGridImg::AppendTotalHighlightRegionL(TRegion &aRegion) const + { + // + // Creates the total selected region by summing all the rectangles + // of the cursor or the highlighted regions (including the anchor) + // + TRect clipRect=MainRect(); + AppendPartialHighlightRegionL(aRegion,clipRect); + TBool isHorizontalTitleLine=iGridLay->IsHorizontalTitleLine(); + TBool isVerticalTitleLine=iGridLay->IsVerticalTitleLine(); + if (isHorizontalTitleLine && isVerticalTitleLine) + { + clipRect.SetRect(iTitlePoint,iMainPoint-TPoint(1,1)); + if (clipRect.IsNormalized()) + AppendPartialHighlightRegionL(aRegion,clipRect,ETitleRef,ETitleRef); + } + if (isHorizontalTitleLine) + { + clipRect.SetRect(iMainPoint.iX,iTitlePoint.iY,iGridRect.iBr.iX,iMainPoint.iY-1); + if (clipRect.IsNormalized()) + AppendPartialHighlightRegionL(aRegion,clipRect,EMainRef,ETitleRef); + } + if (isVerticalTitleLine) + { + clipRect.SetRect(iTitlePoint.iX,iMainPoint.iY,iMainPoint.iX-1,iGridRect.iBr.iY); + if (clipRect.IsNormalized()) + AppendPartialHighlightRegionL(aRegion,clipRect,ETitleRef,EMainRef); + } + } + +void CGridImg::RemoveRowLabelFromRegionL(TInt aRow,TRegion& aRegion) const +// +// Returns ETrue if error + { + TInt tlY=iGridLay->VisibleRowToYVal(aRow); + if (tlY<0) + return; // Not on screen + TRect rect(iGridRect.iTl.iX,tlY,iTitlePoint.iX,tlY+iGridLay->RowHeightInPixels(aRow)); + aRegion.SubRect(rect); + if (aRegion.CheckError()) + User::Leave(KErrNoMemory); + } + +void CGridImg::CleanupGc(TAny* aObject) + { + ((CGridImg*)aObject)->DeleteGc(); + } + +EXPORT_C void CGridImg::DrawL(CGraphicsContext* aGc) const +/** Draws the entire grid and its contents. + +@param aGc The graphics context to be used for drawing. */ + { + ((CGridImg*)this)->CreateGc(aGc); + iGcPtr->SetClippingRect(iGridRect); //Needed because of border round grid + ResetGcToDefault(iGcPtr); + CleanupStack::PushL(TCleanupItem(CleanupGc,(CGridImg*)this)); + DrawAllGridLabelsL(); + iGcPtr->Reset(); + if (iGridLay->IsAutoClearGridCells()) +//-> + TGridUtils::FillRect(iGcPtr, iGridLay->GridColors().iBackground, TRect(iTitlePoint,iGridRect.iBr)); +// TGridUtils::FillRect(iGcPtr,KRgbGridBackground,TRect(iTitlePoint,iGridRect.iBr)); +//-> + DrawAllGridLinesAndCellsL(); //Handles its own clipping + RRegion region; + CleanupClose::PushL(region); + AppendTotalHighlightRegionL(region); + CleanupStack::Pop(2); // region + gc cleanup + HighlightRegion(region); + region.Close(); + DrawVerticalTitleLine(); + DrawHorizontalTitleLine(); + ((CGridImg*)this)->DeleteGc(); + CONST_CAST(CGridImg*,this)->DrawResizingDragHiglights(iGridRect); + } + +#if !defined(__WINC__) +LOCAL_C void EndRedraw(TAny* aObject) + { + ((RWindow*)aObject)->EndRedraw(); + } +#endif + +void CGridImg::BeginRedrawAndDrawL() const + { +#if !defined(__WINC__) + iWin->Invalidate(); + iWin->BeginRedraw(); + CleanupStack::PushL(TCleanupItem(EndRedraw,iWin)); + DrawL(iGc); + CleanupStack::PopAndDestroy(); +#endif + } + +EXPORT_C void CGridImg::DrawL(CGraphicsContext* aGc,const TRect& aRect) const +/** Draws the grid and its contents that are visible within the specified +rectangle. + +@param aGc The graphics context to be used for drawing. +@param aRect Drawing of the grid is restricted to this rectangle. */ + { + if (aRect.Contains(iGridRect.iTl) && aRect.Contains(iGridRect.iBr)) + { + DrawL(aGc); + return; + } + ((CGridImg*)this)->CreateGc(aGc); + ResetGcToDefault(iGcPtr); + + TRangeRef titleRange=iGridLay->TitleRange(); + TBool isHorizontalTitleLine=iGridLay->IsHorizontalTitleLine(); + TBool isVerticalTitleLine=iGridLay->IsVerticalTitleLine(); + TRect clippingRect(iGridRect.iTl,iMainPoint); //Top left quarter of grid + CleanupStack::PushL(TCleanupItem(CleanupGc,(CGridImg*)this)); + if (aRect.Intersects(clippingRect)) + { + clippingRect.Intersection(aRect); + iGcPtr->SetClippingRect(clippingRect); + DrawTopLeftGridLabelL(); + if (isVerticalTitleLine) + DrawTopGridLabelsL(titleRange.iFrom.iCol,titleRange.iTo.iCol-1,ETitleRef); + if (isHorizontalTitleLine) + { + DrawSideGridLabelsL(titleRange.iFrom.iRow,titleRange.iTo.iRow,ETitleRef); + } + iGcPtr->Reset(); + if (isVerticalTitleLine && isHorizontalTitleLine) + { + clippingRect.SetRect(iTitlePoint,iMainPoint); + clippingRect.Intersection(aRect); + if (iGridLay->IsAutoClearGridCells()) +//-> + TGridUtils::FillRect(iGcPtr, iGridLay->GridColors().iBackground, clippingRect); +// TGridUtils::FillRect(iGcPtr,KRgbGridBackground,clippingRect); +//-> + DrawGridLinesAndCellsInRangeL(titleRange,clippingRect,ETitleRef,ETitleRef); + } + } + + TInt borderCorr=(iGridLay->IsEncroachingCellBorders()) ? 1 : 0; + TRangeRef range; + clippingRect.SetRect(iMainPoint.iX,iGridRect.iTl.iY,iGridRect.iBr.iX,iMainPoint.iY);//Top right quarter + if (aRect.Intersects(clippingRect)) + { + clippingRect.Intersection(aRect); + iGcPtr->SetClippingRect(clippingRect); + range.iFrom.iCol=iGridLay->XValToColumn(clippingRect.iTl.iX); + range.iTo.iCol=iGridLay->XValToColumn(clippingRect.iBr.iX+borderCorr); + DrawTopGridLabelsL(range.iFrom.iCol,range.iTo.iCol); + iGcPtr->Reset(); + if (isHorizontalTitleLine) + { + range.iFrom.iRow=titleRange.iFrom.iRow; + range.iTo.iRow=titleRange.iTo.iRow; + clippingRect.SetRect(iMainPoint.iX,iTitlePoint.iY,iGridRect.iBr.iX,iMainPoint.iY); + clippingRect.Intersection(aRect); + if (iGridLay->IsAutoClearGridCells()) +//-> + TGridUtils::FillRect(iGcPtr,iGridLay->GridColors().iBackground,clippingRect); +// TGridUtils::FillRect(iGcPtr,KRgbGridBackground,clippingRect); +//-> + DrawGridLinesAndCellsInRangeL(range,clippingRect,EMainRef,ETitleRef); + } + } + + clippingRect.SetRect(iGridRect.iTl.iX,iMainPoint.iY,iMainPoint.iX,iGridRect.iBr.iY);//Bottom left quarter + if (aRect.Intersects(clippingRect)) + { + clippingRect.Intersection(aRect); + iGcPtr->SetClippingRect(clippingRect); + range.iFrom.iRow=iGridLay->YValToRow(clippingRect.iTl.iY); + range.iTo.iRow=iGridLay->YValToRow(clippingRect.iBr.iY+borderCorr); + DrawSideGridLabelsL(range.iFrom.iRow,range.iTo.iRow); + iGcPtr->Reset(); + if (isVerticalTitleLine) + { + range.iFrom.iCol=titleRange.iFrom.iCol; + range.iTo.iCol=titleRange.iTo.iCol; + clippingRect.SetRect(iTitlePoint.iX,iMainPoint.iY,iMainPoint.iX,iGridRect.iBr.iY); + clippingRect.Intersection(aRect); + if (iGridLay->IsAutoClearGridCells()) +//-> + TGridUtils::FillRect(iGcPtr,iGridLay->GridColors().iBackground,clippingRect); +// TGridUtils::FillRect(iGcPtr,KRgbGridBackground,clippingRect); +//-> + DrawGridLinesAndCellsInRangeL(range,clippingRect,ETitleRef,EMainRef); + } + } + + clippingRect.SetRect(iMainPoint,iGridRect.iBr); //Bottom right(main) quarter of grid + if (aRect.Intersects(clippingRect)) + { + clippingRect.Intersection(aRect); + range.iFrom = iGridLay->PointToCell(clippingRect.iTl); + range.iTo = iGridLay->PointToCell(clippingRect.iBr+TPoint(borderCorr,borderCorr)); + if (iGridLay->IsAutoClearGridCells()) +//-> + TGridUtils::FillRect(iGcPtr,iGridLay->GridColors().iBackground,clippingRect); +// TGridUtils::FillRect(iGcPtr,KRgbGridBackground,clippingRect); +//-> + DrawGridLinesAndCellsInRangeL(range,clippingRect); + } + clippingRect=iGridRect; + clippingRect.Intersection(aRect); + iGcPtr->SetClippingRect(clippingRect); + RRegion region; + CleanupClose::PushL(region); + AppendTotalHighlightRegionL(region); + CleanupStack::Pop(2); // region + gc cleanup + HighlightRegion(region); + region.Close(); + DrawVerticalTitleLine(); + DrawHorizontalTitleLine(); + iGcPtr->CancelClippingRect(); + ((CGridImg*)this)->DeleteGc(); + CONST_CAST(CGridImg*,this)->DrawResizingDragHiglights(aRect); + } + +#if defined(__WINC__) +void CGridImg::BeginRedrawAndDrawL(const TRect& /*aRect*/) const + {} // shouldn't be called under WINC +#else + +void CGridImg::BeginRedrawAndDrawL(const TRect& aRect) const + { + iWin->Invalidate(aRect); + iWin->BeginRedraw(aRect); + CleanupStack::PushL(TCleanupItem(EndRedraw,iWin)); + DrawL(iGc,aRect); + CleanupStack::PopAndDestroy(); + } +#endif + +EXPORT_C void CGridImg::PrintGridLinesAndCellsInRangeL(CGraphicsContext* aPrinterGc,const TRangeRef& aRange, + TInt aScaleFactor) const +// +// Assumes aPrinterGc is active for drawing to +/** Prints the grid lines and cells in the specified range. + +@param aPrinterGc The printer graphics context. +@param aRange The cell range. +@param aScaleFactor The scale factor. A value of: 2, scales down by a half; +4, scales down by a quarter, etc. */ + { + __ASSERT_DEBUG(aPrinterGc!=NULL,Panic(EGridImgInvalidGC)); + + TRangeRef visRange=iGridLay->VisibleRange(); + TPoint endPoint=iGridLay->CellToPoint(visRange.iTo+TCellRef(1,1)); + TRect borderRect(iGridRect.iTl,endPoint); + TPoint titlePoint=iTitlePoint; + if (aScaleFactor!=EScaleOneToOne) + { + ScaleDown(borderRect.iTl,aScaleFactor); + ScaleDown(borderRect.iBr,aScaleFactor); + ScaleDown(titlePoint,aScaleFactor); + } + borderRect.iTl-=TPoint(1,1); + TPoint realTlPoint=iGridLay->CellToPoint(aRange.iFrom); + TBool doColumns=aRange.iTo.iCol>=aRange.iFrom.iCol; + TBool doRows=aRange.iTo.iRow>=aRange.iFrom.iRow; + TBool printBorderRect=EFalse; + if (iGridLay->IsPrintedLabels()) + { + TBool isSideLabels=iGridLay->IsSideLabels(); + TBool isTopLabels=iGridLay->IsTopLabels(); + if (isSideLabels && isTopLabels && aRange.iFrom==visRange.iFrom) // i.e. is top band + { + TRect rect(iGridRect.iTl,iTitlePoint); + ScaleDown(rect.iTl,aScaleFactor); + ScaleDown(rect.iBr,aScaleFactor); + rect.Resize(-1,-1); +//-> +// iGridLabelImg->DrawTopLeftLabelL(aPrinterGc,rect); + iGridLabelImg->DrawTopLeftLabelL(aPrinterGc, rect, iGridLay->GridColors().iBackground); +//-> + printBorderRect=ETrue; + } + if (isTopLabels && doColumns) + { + TInt realPos=realTlPoint.iX; + TRect line(realPos*EScaleOneToOne/aScaleFactor,borderRect.iTl.iY+1,0,titlePoint.iY-1); + for (TInt ii=aRange.iFrom.iCol;iiColumnWidthInPixels(ii); + line.iBr.iX=realPos*EScaleOneToOne/aScaleFactor-1; + iGridLabelImg->DrawColLabelL(aPrinterGc,ii,line); + line.iTl.iX=line.iBr.iX; +//-> + aPrinterGc->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// aPrinterGc->SetPenColor(KRgbGridLabelSeparators); +//-> + aPrinterGc->DrawLine(line.iTl,line.iBr); + line.iTl.iX++; + } + realPos+=iGridLay->ColumnWidthInPixels(aRange.iTo.iCol); + line.iBr.iX=realPos*EScaleOneToOne/aScaleFactor-1; + iGridLabelImg->DrawColLabelL(aPrinterGc,aRange.iTo.iCol,line); +//-> + aPrinterGc->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// aPrinterGc->SetPenColor(KRgbGridLabelSeparators); +//-> + aPrinterGc->DrawLine(TPoint(borderRect.iTl.iX,titlePoint.iY-1), + TPoint(borderRect.iBr.iX,titlePoint.iY-1)); + printBorderRect=ETrue; + } + if (isSideLabels && doRows) + { + TInt realPos=realTlPoint.iY; + TRect line(borderRect.iTl.iX+1,realPos*EScaleOneToOne/aScaleFactor,titlePoint.iX-1,0); + for (TInt ii=aRange.iFrom.iRow;iiRowHeightInPixels(ii); + line.iBr.iY=realPos*EScaleOneToOne/aScaleFactor-1; + iGridLabelImg->DrawRowLabelL(aPrinterGc,ii,line); + line.iTl.iY=line.iBr.iY; +//-> + aPrinterGc->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// aPrinterGc->SetPenColor(KRgbGridLabelSeparators); +//-> + aPrinterGc->DrawLine(line.iTl,line.iBr); + line.iTl.iY++; + } + realPos+=iGridLay->RowHeightInPixels(aRange.iTo.iRow); + line.iBr.iY=realPos*EScaleOneToOne/aScaleFactor-1; + iGridLabelImg->DrawRowLabelL(aPrinterGc,aRange.iTo.iRow,line); +//-> + aPrinterGc->SetPenColor(iGridLay->GridColors().iLabelSeparators); +// aPrinterGc->SetPenColor(KRgbGridLabelSeparators); +//-> + aPrinterGc->DrawLine(TPoint(titlePoint.iX-1,borderRect.iTl.iY), + TPoint(titlePoint.iX-1,borderRect.iBr.iY)); + printBorderRect=ETrue; + } + } + + if (iGridLay->IsPrintedGridLines()) + { +//-> +// aPrinterGc->SetPenColor(KRgbGridForeground); // prints black not gray as on screen + aPrinterGc->SetPenColor(iGridLay->GridColors().iForeground); // prints black not gray as on screen +//-> + if (iGridLay->IsVerticalGridLines() && doColumns) + { + TInt realPos=realTlPoint.iX; + TRect line(0,titlePoint.iY,0,borderRect.iBr.iY-1); + for (TInt ii=aRange.iFrom.iCol;iiColumnWidthInPixels(ii); + line.iTl.iX=line.iBr.iX=realPos*EScaleOneToOne/aScaleFactor-1; + aPrinterGc->DrawLine(line.iTl,line.iBr); + } + printBorderRect=ETrue; + } + if (iGridLay->IsHorizontalGridLines() && doRows) + { + TInt realPos=realTlPoint.iY; + TRect line(titlePoint.iX,0,borderRect.iBr.iX-1,0); + for (TInt ii=aRange.iFrom.iRow;iiRowHeightInPixels(ii); + line.iTl.iY=line.iBr.iY=realPos*EScaleOneToOne/aScaleFactor-1; + aPrinterGc->DrawLine(line.iTl,line.iBr); + } + printBorderRect=ETrue; + } + } + if (printBorderRect) + { +//-> +// aPrinterGc->SetPenColor(KRgbGridForeground); + aPrinterGc->SetPenColor(iGridLay->GridColors().iForeground); +//-> + + aPrinterGc->DrawRect(borderRect); + } + if (doRows && doColumns) + DrawCellsToGcL(aPrinterGc,aRange,TRect(titlePoint,borderRect.iBr),realTlPoint,aScaleFactor); + } + +void CGridImg::ScaleDown(TPoint& aPoint,TInt aScaleFactor) const + { + aPoint.iX=aPoint.iX*EScaleOneToOne/aScaleFactor; + aPoint.iY=aPoint.iY*EScaleOneToOne/aScaleFactor; + } + +void CGridImg::ResetGcToDefault(CGraphicsContext* aGc) const +// +// Should be called if the gc may have changed outside CGridImg since the private +// functions assume these settings. + { + aGc->SetPenStyle(CGraphicsContext::ESolidPen); + aGc->SetPenSize(TSize(1,1)); + aGc->SetBrushStyle(CGraphicsContext::ENullBrush); + } + +EXPORT_C void CGridImg::SetCursorPosL(const TCellRef& aCursorPos) +/** Sets the new position of the cursor. + +This is the proposed position that the cursor would occupy after a keypress. + +@param aCursorPos The cell reference of the new cursor position. */ + { + iNewCursorPos=aCursorPos; + if (!iGridLay->LimitCell(iNewCursorPos)) + { + iNewCursorPos=iCursorPos; + return; + } + DrawCursorOrRegionL(EIsAbsoluteMove); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::SetAnchorPosL(const TCellRef& aAnchorPos) +/** Sets the cursor's anchor position. + +Note that the cursor's anchor position is unchanged if the specified position +lies outside the currently selected region. + +@param aAnchorPos The cell reference of the cursor's anchor position. */ + { + if (!iSelected->IsCellSelected(iAnchorPos)) + return; //Can't have the anchor outside the selection region + RRegion oldRegion; + CleanupClose::PushL(oldRegion); + AppendTotalHighlightRegionL(oldRegion); + iAnchorPos=aAnchorPos; + if (!iGridLay->LimitCell(iAnchorPos)) + { + oldRegion.Close(); + CleanupStack::Pop(); + return; + } + iNewCursorPos=iCursorPos=iAnchorPos; + HighlightNewRegionFromOldL(oldRegion); + oldRegion.Close(); + CleanupStack::Pop(); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::MoveCursorL(TMoveDirectionAndAmount aCursorMove,TUint aSelectState) +/** Moves the cursor to the specified position. + +The screen is scrolled as necessary. + +@param aCursorMove Defines the direction and the amount by which the cursor +is to be moved. +@param aSelectState Flag. If set to EIsWithSelect, then the cursor may become +part of the selected region. */ + { + TUint flagList=aSelectState&EIsWithSelect; //Filters out any other components + if (!flagList && iSelected->Count()) + iNewCursorPos = iAnchorPos; + TCellRef oldPos=iNewCursorPos; + TMoveDirectionAndAmount pageScroll=EMoveNone; + TRangeRef visRange=iGridLay->VisibleRange(); + TCellRef cellToExpose=visRange.iFrom; + TBool doExposeCol=EFalse; + TInt relCursorPos; + TInt amount; + switch (aCursorMove) + { + case EMoveRowUp: + iGridLay->StepRowBackward(--iNewCursorPos.iRow); + break; + case EMoveRowDown: + iGridLay->StepRowForward(++iNewCursorPos.iRow); + break; + case EMoveColumnLeft: + if (iGridLay->IsRowPermanentlySelected()) + { + --cellToExpose.iCol; + doExposeCol=ETrue; + } + else + iGridLay->StepColumnBackward(--iNewCursorPos.iCol); + break; + case EMoveColumnRight: + if (iGridLay->IsRowPermanentlySelected()) + { + cellToExpose.iCol=visRange.iTo.iCol; + if (iGridLay->IsVisibleToColumnFullyVisible() || visRange.iFrom.iCol==visRange.iTo.iCol) + cellToExpose.iCol++; + doExposeCol=ETrue; + } + else + iGridLay->StepColumnForward(++iNewCursorPos.iCol); + break; + case EMovePageUp: + relCursorPos=iGridLay->RowToYVal(visRange.iFrom.iRow,iNewCursorPos.iRow); + pageScroll=EMovePageDown; + amount=iGridLay->CalcVisibleFromRowAfterPageScroll(pageScroll); + if (amount!=visRange.iFrom.iRow) + { + TInt newCursorRow=iGridLay->YValToNearestRow(amount,relCursorPos); + if (newCursorRow>=iNewCursorPos.iRow) + iGridLay->StepRowBackward(--iNewCursorPos.iRow); + else + iNewCursorPos.iRow=newCursorRow; + } + else + iNewCursorPos.iRow=Min(visRange.iFrom.iRow,iNewCursorPos.iRow-1); + iGridLay->LimitRowToVisible(iNewCursorPos.iRow); + break; + case EMovePageDown: + relCursorPos=iGridLay->RowToYVal(visRange.iFrom.iRow,iNewCursorPos.iRow); + pageScroll=EMovePageUp; + amount=iGridLay->CalcVisibleFromRowAfterPageScroll(pageScroll); + if (amount!=visRange.iFrom.iRow) + { + TInt newCursorRow=iGridLay->YValToNearestRow(amount,relCursorPos); + if (newCursorRow<=iNewCursorPos.iRow) + iGridLay->StepRowForward(++iNewCursorPos.iRow); + else + iNewCursorPos.iRow=newCursorRow; + } + else + { + TInt corr=iGridLay->IsVisibleToRowFullyVisible() ? 0 : 1; + iNewCursorPos.iRow=Max(visRange.iTo.iRow-corr,iNewCursorPos.iRow+1); + } + break; + case EMovePageLeft: + relCursorPos=iGridLay->ColumnToXVal(visRange.iFrom.iCol,iNewCursorPos.iCol); + pageScroll=EMovePageRight; + amount=iGridLay->CalcVisibleFromColumnAfterPageScroll(pageScroll); + if (amount!=visRange.iFrom.iCol) + { + TInt newCursorColumn=iGridLay->XValToNearestColumn(amount,relCursorPos); + if (newCursorColumn>=iNewCursorPos.iCol) + iGridLay->StepColumnBackward(--iNewCursorPos.iCol); + else + iNewCursorPos.iCol=newCursorColumn; + } + else + iNewCursorPos.iCol=Min(visRange.iFrom.iCol,iNewCursorPos.iCol-1); + iGridLay->LimitColumnToVisible(iNewCursorPos.iCol); + break; + case EMovePageRight: + relCursorPos=iGridLay->ColumnToXVal(visRange.iFrom.iCol,iNewCursorPos.iCol); + pageScroll=EMovePageLeft; + amount=iGridLay->CalcVisibleFromColumnAfterPageScroll(pageScroll); + if (amount!=visRange.iFrom.iCol) + { + TInt newCursorColumn=iGridLay->XValToNearestColumn(amount,relCursorPos); + if (newCursorColumn<=iNewCursorPos.iCol) + iGridLay->StepColumnForward(++iNewCursorPos.iCol); + else + iNewCursorPos.iCol=newCursorColumn; + } + else + { + TInt corr=iGridLay->IsVisibleToColumnFullyVisible() ? 0 : 1; + iNewCursorPos.iCol=Max(visRange.iTo.iCol-corr,iNewCursorPos.iCol+1); + } + break; + case EMoveRowStart: + case EMoveColumnStart: + case EMoveHome: + if (aCursorMove!=EMoveColumnStart) + { + if (iGridLay->IsRowPermanentlySelected()) + { + cellToExpose.iCol=iGridLay->MinVisibleFromColumn(); + doExposeCol=ETrue; + } + else + { + iNewCursorPos.iCol=iGridLay->MinVisibleFromColumn(); + iGridLay->StepColumnForward(iNewCursorPos.iCol); + } + } + if (aCursorMove!=EMoveRowStart) + { + iNewCursorPos.iRow=(iGridLay->IsIndefiniteRowBoundaries()) + ? -KMaxTInt : iGridLay->MinVisibleFromRow(); + iGridLay->StepRowForward(iNewCursorPos.iRow); + } + break; + case EMoveRowEnd: + case EMoveColumnEnd: + case EMoveEnd: + { + TCellRef fromCell=iGridLay->GridRange().iFrom; + if (aCursorMove!=EMoveColumnEnd) + { + TInt lastCol=fromCell.iCol+iGridLay->ColumnExtent()-1; + if (iGridLay->IsRowPermanentlySelected()) + { + cellToExpose.iCol=lastCol; + doExposeCol=ETrue; + } + else + { + iNewCursorPos.iCol=lastCol; + iGridLay->StepColumnBackward(iNewCursorPos.iCol); + } + } + if (aCursorMove!=EMoveRowEnd) + { + iNewCursorPos.iRow=(iGridLay->IsIndefiniteRowBoundaries()) + ? KMaxTInt : fromCell.iRow+iGridLay->RowExtent()-1; + iGridLay->StepRowBackward(iNewCursorPos.iRow); + } + } + break; + default: + break; + } + iGridLay->LimitCell(iNewCursorPos); + if (oldPos==iNewCursorPos) + flagList|=EIsAtBoundary; + oldPos=iNewCursorPos; + DrawCursorOrRegionL(flagList); + TPoint offset; + if (pageScroll!=EMoveNone) + offset=iGridLay->PageScroll(pageScroll); + cellToExpose.iRow=iCursorPos.iRow; + if (!doExposeCol) + cellToExpose.iCol=iCursorPos.iCol; + if (iGridLay->IsCellOutOfVisibleRange(cellToExpose)) + { + visRange=iGridLay->VisibleRange(); + visRange.iTo.Offset(-1,-1); + iGridLay->StepRowBackward(visRange.iTo.iRow); + iGridLay->StepColumnBackward(visRange.iTo.iCol); + if (iSelected->IsColSelectedLastIndex(cellToExpose.iCol) && + !iGridLay->IsColumnSelectionDisabled()) + { + cellToExpose.iRow=visRange.iFrom.iRow; + } + if ((iSelected->IsRowSelectedLastIndex(cellToExpose.iRow) || iGridLay->IsRowPermanentlySelected()) + && !doExposeCol && !iGridLay->IsRowSelectionDisabled()) + { + cellToExpose.iCol=visRange.iFrom.iCol; + } + offset+=iGridLay->ExposeCell(cellToExpose); + } + ScrollL(offset); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::SetCursorWithPointerL(const TPoint &aPoint,TUint aFlagList) +/** Moves the cursor to an absolute position. + +@param aPoint The absolute position. +@param aFlagList Flag. Can be set to EIsWithDrag. */ + { + TRangeRef visRange(iGridLay->VisibleRange()); + TCellRef cellToExpose = visRange.iFrom; + if (iGridLay->IsVerticalTitleLine()) + { + if (aPoint.iXIsRowSelectedLastIndex(iCursorPos.iRow) + && (aFlagList&EIsWithDrag)) + { + cellToExpose.iCol=iGridLay->TitleRange().iTo.iCol; + } + iXRefPoint=EMainRef; + } + } + else + iXRefPoint=EMainRef; + if (iGridLay->IsHorizontalTitleLine()) + { + if (aPoint.iYIsColSelectedLastIndex(iCursorPos.iCol) + && (aFlagList&EIsWithDrag)) + { + cellToExpose.iRow=iGridLay->TitleRange().iTo.iRow; + } + iYRefPoint=EMainRef; + } + } + else + iYRefPoint=EMainRef; + TPoint offset=iGridLay->ExposeCellToTopLeft(cellToExpose); + ScrollL(offset); + + if (aPoint.iYIsColSelectedLastIndex(iCursorPos.iCol)) + { + if (iGridLay->IsColumnSelectionDisabled()) + { + iDragFlags|=EIsLabelDraggingIgnored; + return; + } + aFlagList|=EIsColumnSelected; + iDragFlags=iDragFlags&~EIsLabelDraggingIgnored; + } + } + if (aPoint.iXIsRowSelectedLastIndex(iCursorPos.iRow)) + { + if (iGridLay->IsRowPermanentlySelected() && !(aFlagList&EIsWithDrag)) + iDragFlags|=EIsSidewaysScrollIgnored; + else if (iGridLay->IsRowSelectionDisabled()) + { + iDragFlags|=EIsLabelDraggingIgnored; + return; + } + else + aFlagList|=EIsRowSelected; + iDragFlags=iDragFlags&~EIsLabelDraggingIgnored; + } + } + else + { + iDragFlags=iDragFlags&~EIsSidewaysScrollIgnored; + if (aPoint.iY>=iTitlePoint.iY) //ie not on the labels + iDragFlags=iDragFlags&~EIsLabelDraggingIgnored; + } + iNewCursorPos=RelativePointToCell(aPoint,iXRefPoint,iYRefPoint); + iGridLay->LimitCell(iNewCursorPos); + if (iCursorPos==iNewCursorPos && !iSelected->Count() && + !(aFlagList&(EIsRowSelected|EIsColumnSelected|EIsWithControl))) + { + return; // Don't need to do anything in this case + } + + cellToExpose = iNewCursorPos; + if (iSelected->IsColSelectedLastIndex(iCursorPos.iCol) && (aFlagList&EIsWithDrag)) + cellToExpose.iRow = visRange.iFrom.iRow; + if ((iSelected->IsRowSelectedLastIndex(iCursorPos.iRow) && (aFlagList&EIsWithDrag) + && !iGridLay->IsRowPermanentlySelected()) || iDragFlags&EIsSidewaysScrollIgnored) + { + cellToExpose.iCol = visRange.iFrom.iCol; + } + TBool expose = EFalse; + if (aFlagList&EIsWithDrag) + { + if ((aPoint.iXiGridRect.iBr.iX) + expose=ETrue; + else + cellToExpose.iCol=visRange.iFrom.iCol; + if ((aPoint.iYiGridRect.iBr.iY) + expose=ETrue; + else + cellToExpose.iRow=visRange.iFrom.iRow; + } + + aFlagList|=EIsAbsoluteMove; + DrawCursorOrRegionL(aFlagList); + if (expose) + { + offset=iGridLay->ExposeCell(cellToExpose); + ScrollL(offset); + } + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::ResetSelectedL() +/** Clears the selected region. */ + { + if (!iSelected->Count()) + return; + RRegion oldRegion; + CleanupClose::PushL(oldRegion); + AppendTotalHighlightRegionL(oldRegion); + iNewCursorPos=iCursorPos=iAnchorPos; + iSelected->Reset(); + HighlightNewRegionFromOldL(oldRegion); + oldRegion.Close(); + CleanupStack::Pop(); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::AddRangeToSelectedL(const TRangeRef& aRange,TSelectType aType) +/** Adds the specified range to, or replaces, the currently selected region. + +The range can be added to the existing selected region or it can replace the +existing selected region. + +@param aRange The range to be added. +@param aType Indicates whether the existing selected region is to be reset +(i.e. emptied) before adding the new range. */ + { + RRegion oldRegion; + CleanupClose::PushL(oldRegion); + AppendTotalHighlightRegionL(oldRegion); + if (aType==ESelectOverwrite) + iSelected->Reset(); + iNewCursorPos=iCursorPos=aRange.iTo; + iAnchorPos=aRange.iFrom; + iSelected->AddCellRangeL(aRange); + HighlightNewRegionFromOldL(oldRegion); + oldRegion.Close(); + CleanupStack::Pop(); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::AddRegionToSelectedL(const CArrayFix* aCellRegion,TSelectType aType) +/** Adds the specified region to, or replaces, the currently selected region. + +The region can be added to the existing selected region, or it can replace +the existing selected region. + +@param aCellRegion A set of ranges that form the region to be added. +@param aType Indicates whether the existing selected region is to be reset +(i.e. emptied) before adding the new region. */ + { + RRegion oldRegion; + CleanupClose::PushL(oldRegion); + AppendTotalHighlightRegionL(oldRegion); + if (aType==ESelectOverwrite) + iSelected->Reset(); + TInt count=aCellRegion->Count(); + if (!count) + iNewCursorPos=iCursorPos=iAnchorPos=iGridLay->GridRange().iFrom; + else + { + TRangeRef lastRange=(*aCellRegion)[count-1]; + iNewCursorPos=iCursorPos=lastRange.iTo; + iAnchorPos=lastRange.iFrom; + for (TInt ii=0;iiAddCellRangeL((*aCellRegion)[ii]); + } + HighlightNewRegionFromOldL(oldRegion); + oldRegion.Close(); + CleanupStack::Pop(); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::AddRowToSelectedL(TInt aRow,TSelectType aType) +/** Adds a row to, or replaces, the currently selected region. + +The row can be added to the existing selected region, or it can replace the +existing selected region. + +@param aRow The row to be added. +@param aType Indicates whether the existing selected region is to be reset +(i.e. emptied) before adding the new region. */ + { + RRegion oldRegion; + CleanupClose::PushL(oldRegion); + AppendTotalHighlightRegionL(oldRegion); + if (aType==ESelectOverwrite) + iSelected->Reset(); + iAnchorPos.iRow=iCursorPos.iRow=iNewCursorPos.iRow=aRow; + iAnchorPos.iCol=iGridLay->VisibleRange().iFrom.iCol; + iNewCursorPos.iCol=iCursorPos.iCol=iGridLay->GridRange().iTo.iCol; + iSelected->AddRowL(aRow); + HighlightNewRegionFromOldL(oldRegion); + oldRegion.Close(); + CleanupStack::Pop(); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +EXPORT_C void CGridImg::AddColToSelectedL(TInt aCol,TSelectType aType) +/** Adds a column to, or replaces, the currently selected region. + +The column can be added to the existing selected region, or it can replace +the existing selected region. + +@param aCol The column to be added. +@param aType Indicates whether the existing selected region is to be reset +(i.e. emptied) before adding the new region. */ + { + RRegion oldRegion; + CleanupClose::PushL(oldRegion); + AppendTotalHighlightRegionL(oldRegion); + if (aType==ESelectOverwrite) + iSelected->Reset(); + iAnchorPos.iCol=iCursorPos.iCol=iNewCursorPos.iCol=aCol; + iAnchorPos.iRow=iGridLay->VisibleRange().iFrom.iRow; + iNewCursorPos.iRow=iCursorPos.iRow=iGridLay->GridRange().iTo.iRow; + iSelected->AddColL(aCol); + HighlightNewRegionFromOldL(oldRegion); + oldRegion.Close(); + CleanupStack::Pop(); + if (iCursorMoveCallBack) + iCursorMoveCallBack->HandleCursorMoveL(); + } + +void CGridImg::HighlightNewRegionFromOldL(const TRegion& aOldRegion) +// +// returns ETrue if there's an error + { + RRegion newRegion; + CleanupClose::PushL(newRegion); + AppendTotalHighlightRegionL(newRegion); + HighlightMinRegionL(aOldRegion,newRegion); + CleanupStack::Pop(); + newRegion.Close(); + } + +EXPORT_C void CGridImg::CheckSideLabelWidthAndScrollL() +/** Checks the side label width and, if changed, scrolls the screen. */ + { + TInt offset=CheckSideLabelWidth(); +#if !defined(__WINC__) + if (offset) + { + TRect rect(iGridRect.iTl.iX,iGridRect.iTl.iY,iTitlePoint.iX-1,iGridRect.iBr.iY); + iWin->Scroll(iGridRect,TPoint(offset,0)); + BeginRedrawAndDrawL(rect); + if (offset<0) + { + rect.SetRect(iGridRect.iBr.iX+offset,iGridRect.iTl.iY,iGridRect.iBr.iX,iGridRect.iBr.iY); + BeginRedrawAndDrawL(rect); + } + } +#endif + } + +EXPORT_C TInt CGridImg::CheckSideLabelWidth() +/** Checks whether there has been a change in the width of the side label. + +@return The difference between the new width and the old width (new width +- old width). */ + { + if (iGridLay->IsSideLabels()) + { + TInt oldWidth=iTitlePoint.iX-iGridRect.iTl.iX; + TInt newWidth=SideLabelWidthInPixels(); + if (oldWidth!=newWidth) + { + ResetReferencePoints(); + iGridLay->ResetVisibleToCell(); + return (newWidth-oldWidth); + } + } + return 0; + } + +EXPORT_C TInt CGridImg::SideLabelWidthInPixels() const +/** Gets the width of the side label. + +@return The width of the side label, in pixels. */ + { + if (iGridLabelImg==NULL) + return 0; + TRangeRef visRange=iGridLay->VisibleRange(); + if (!iGridLay->LimitRow(visRange.iFrom.iRow)) + return 0; + return iGridLabelImg->SideLabelWidthInPixels(visRange.iFrom.iRow,visRange.iTo.iRow); + } + +EXPORT_C TInt CGridImg::MaxSideLabelWidthInPixels() const +/** Gets the maximum width of the side label. + +@return The maximum width of the side label, in pixels. */ + { + if (iGridLabelImg==NULL) + return 0; + TInt firstRow; + if (!iGridLay->RequestRow(-KMaxTInt,firstRow)) + return 0; + return iGridLabelImg->SideLabelWidthInPixels(firstRow,firstRow+iGridLay->RowExtent()-1); + } + +EXPORT_C TInt CGridImg::TopLabelHeightInPixels() const +/** Gets the height of the top labels. + +@return The height of the top labels, in pixels. */ + { + if (iGridLabelImg==NULL) + return 0; + return iGridLabelImg->TopLabelHeightInPixels(); + } + +#if defined(__WINC__) + +// All these functions are inappropriate under WINC +EXPORT_C void CGridImg::FinishLabelDragL() + {} + +EXPORT_C TBool CGridImg::StartLabelDrag(const TPoint& /*aPoint*/) + { return EFalse; } + +TBool CGridImg::ScanColumnsForDrag(TInt /*aFromColumn*/,TInt /*aToColumn*/,TInt /*aPointerPos*/,TInt& /*aPrevious*/,TInt& /*aCurrent*/) + { return EFalse; } + +TBool CGridImg::ScanRowsForDrag(TInt /*aFromRow*/,TInt /*aToRow*/,TInt /*aPointerPos*/,TInt& /*aPrevious*/,TInt& /*aCurrent*/) + { return EFalse; } + +EXPORT_C TBool CGridImg::UpdateLabelDrag(const TPoint& /*aPoint*/) + { return EFalse; } + +void CGridImg::DrawArrowsToInMemoryBitmap(TArrows /*aArrows*/) + {} + +void CGridImg::DrawDraggingHighlight(const TRect /*aLine*/,TDragDraw /*aDragDraw*/) + {} + +EXPORT_C void CGridImg::ScrollL(const TPoint& /*aOffset*/) + {} +#else + +EXPORT_C void CGridImg::FinishLabelDragL() +/** Deals with the end of a drag operation. + +Typically, the function is called whan handling a pointer event in a control. + +The function removes the dotted drag line indicating a drag operation, and, +if necessary, updates the column width/row height, and then scrolls and redraws +the necessary regions. + +@see StartLabelDrag() */ + { + // + // Erases the two dotted drag lines if necessary, updates the column/row width/height then scrolls + // and redraws the necessary regions. The relevant member variables are also set to zero. + // + if (iDragDim == ENoDrag) + return; + TRect line1 = iGridRect; + TRect line2 = iGridRect; + TInt oldValue; + TInt prevDragPos; + TRangeRef titleRange=iGridLay->TitleRange(); + if (iDragDim == EXDrag) + { + prevDragPos = ((iGridLay->IsVerticalTitleLine() && iDragLabel<=titleRange.iTo.iCol) + ? iGridLay->TitleColumnToXVal(iDragLabel) : iGridLay->ColumnToXVal(iDragLabel))-1; + line1.iTl.iX = line1.iBr.iX = prevDragPos; + line2.iTl.iX = line2.iBr.iX = iCurrentDragPos; + oldValue = iGridLay->ColumnWidthInPixels(iDragLabel); + } + else + { + prevDragPos = ((iGridLay->IsHorizontalTitleLine() && iDragLabel<=titleRange.iTo.iRow) + ? iGridLay->TitleRowToYVal(iDragLabel) : iGridLay->RowToYVal(iDragLabel))-1; + line1.iTl.iY = line1.iBr.iY = prevDragPos; + line2.iTl.iY = line2.iBr.iY = iCurrentDragPos; + oldValue = iGridLay->RowHeightInPixels(iDragLabel); + } + CreateGc(iGc); + iGc->SetClippingRect(iGridRect); + DrawDraggingHighlight(line1,EDragDrawWithoutBitmap); + DrawDraggingHighlight(line2,EDragDrawWithBitmap); + delete iDragBmp; + iDragBmp=NULL; + DeleteGc(); + iCurrentDragPos = Max(iCurrentDragPos,prevDragPos); + TInt newValue = iCurrentDragPos-prevDragPos; + TInt minValue=(iDragDim==EXDrag) ? iGridLay->MinColumnWidthInPixels() : iGridLay->MinRowHeightInPixels(); + newValue=Max(newValue,minValue); + if (oldValue!=newValue) + { + TRect validRect=iGridRect; + TRect scrollRect=iGridRect; + TPoint offset; + TBool doScroll=EFalse; + TBool newPagination=EFalse; + TBool clearPagination=EFalse; + if (iGridLay->IsPaginated()) + { + if (!iGridLay->IsAutoPagination()) + clearPagination=ETrue; + newPagination=ETrue; + } + if (iDragDim==EXDrag) + { + if (iGridLay->IsUniformColumnWidth() || (iSelected->IsRangeSelected(iGridLay->GridRange()) + && !iGridLay->IsColumnSelectionDisabled())) + { + if (newValue==0) + goto DragEnd; + validRect.iTl.iX=iTitlePoint.iX; + iGridLay->SetDefaultColumnWidthInPixels(newValue); + iGridLay->SetColumnWidthsToDefault(); + } + else if (iSelected->IsColSelected(iDragLabel) && !iGridLay->IsColumnSelectionDisabled()) + { + validRect.iTl.iX=iTitlePoint.iX; + TInt count=iSelected->Count(); + for (TInt ii=0;iiIsColSelected(range.iFrom.iCol,ii)) + { + if ((range.iTo.iCol-range.iFrom.iCol)>CGridLay::EMaxArrayChanges) + continue; + for (;range.iFrom.iCol<=range.iTo.iCol;range.iFrom.iCol++) + iGridLay->SetColumnWidthInPixelsL(range.iFrom.iCol,newValue); + } + } + } + else + { + validRect.iTl.iX = (clearPagination) ? iTitlePoint.iX : + Max(prevDragPos-1,iTitlePoint.iX); + if (!iGridLay->IsColumnBursting() && !newPagination) + { + doScroll=ETrue; + validRect.iBr.iX = iCurrentDragPos+2; + scrollRect.iTl.iX=Max(Min(prevDragPos+oldValue+2,iCurrentDragPos+1),iTitlePoint.iX); + offset.iX = newValue-oldValue; + } + iGridLay->SetColumnWidthInPixelsL(iDragLabel,newValue); + } + } + else + { + if (iGridLay->IsUniformRowHeight() || (iSelected->IsRangeSelected(iGridLay->GridRange()) + && !iGridLay->IsRowSelectionDisabled())) + { + if (newValue==0) + goto DragEnd; + validRect.iTl.iY=iTitlePoint.iY; + iGridLay->SetDefaultRowHeightInPixels(newValue); + iGridLay->SetRowHeightsToDefault(); + } + else if (iSelected->IsRowSelected(iDragLabel) && !iGridLay->IsRowSelectionDisabled()) + { + validRect.iTl.iY=iTitlePoint.iY; + TInt count=iSelected->Count(); + for (TInt ii=0;iiIsRowSelected(range.iFrom.iRow,ii)) + { + if ((range.iTo.iRow-range.iFrom.iRow)>CGridLay::EMaxArrayChanges) + continue; + for (;range.iFrom.iRow<=range.iTo.iRow;range.iFrom.iRow++) + iGridLay->SetRowHeightInPixelsL(range.iFrom.iRow,newValue); + } + } + } + else + { + validRect.iTl.iY = (clearPagination) ? iTitlePoint.iY : + Max(prevDragPos-1,iTitlePoint.iY); + if (!newPagination) + { + doScroll=ETrue; + validRect.iBr.iY = iCurrentDragPos+2; + scrollRect.iTl.iY=Max(Min(prevDragPos+oldValue+2,iCurrentDragPos+1),iTitlePoint.iY); + offset.iY = newValue-oldValue; + } + iGridLay->SetRowHeightInPixelsL(iDragLabel,newValue); + } + } + iGridLay->NotifyPaginationOutOfDateL(); + if (doScroll) + iWin->Scroll(scrollRect,offset); + validRect.Intersection(iGridRect); + BeginRedrawAndDrawL(validRect); + if ((offset.iX<0 && !iGridLay->IsColumnBursting()) || offset.iY<0) + { + if (offset.iX<0) + { + validRect.iBr.iX = iGridRect.iBr.iX; + validRect.iTl.iX = validRect.iBr.iX+offset.iX; + } + else + { + validRect.iBr.iY = iGridRect.iBr.iY; + validRect.iTl.iY = validRect.iBr.iY+offset.iY; + } + BeginRedrawAndDrawL(validRect); + } + CheckSideLabelWidthAndScrollL(); + if (!newValue && !iSelected->Count()) + { + if (iDragDim==EXDrag) + { + if (iDragLabel==iCursorPos.iCol) + MoveCursorL(EMoveColumnRight,!EIsWithSelect); //2nd param=0 + } + else + { + if (iDragLabel==iCursorPos.iRow) + MoveCursorL(EMoveRowDown,!EIsWithSelect); + } + } + } +DragEnd: + iCurrentDragPos = iDragLabel = iDragDiff = 0; + iDragDim = ENoDrag; + } + +EXPORT_C TBool CGridImg::StartLabelResize(TBool aIsColumnLabel, TInt aIndex) +/** Begins the resizing of a column or a row. + +@param aIsColumnLabel Indicates whether a column or row is to be resized: +specify ETrue for a column; specify EFalse for a row. +@param aIndex Identifes the row or column to be resized. This value increases +from left to right for a column, and from top to bottom for a row. +@return True, if resizing has begun; false otherwise. */ + { + TInt widthOrHeight=0; + TRect line1 = iGridRect; + TRect line2 = iGridRect; + TRangeRef visibleRange=iGridLay->VisibleRange(); + iDragDim=ENoDrag; + if(aIsColumnLabel && aIndex>=visibleRange.iFrom.iCol && aIndexIsTopLabelDragDisabled()) + { + iDragLabel=aIndex; + iDragDim = EXDrag; + line1.iTl.iX=line1.iBr.iX=iGridLay->ColumnToXVal(aIndex)-1; + widthOrHeight=iGridLay->ColumnWidthInPixels(aIndex); + iCurrentDragPos=line2.iTl.iX=line2.iBr.iX=line1.iTl.iX+widthOrHeight; + } + else if(!aIsColumnLabel && aIndex>=visibleRange.iFrom.iRow && + aIndexIsSideLabelDragDisabled()) + { + iDragLabel=aIndex; + iDragDim = EYDrag; + line1.iTl.iY=line1.iBr.iY=iGridLay->RowToYVal(aIndex)-1; + widthOrHeight=iGridLay->RowHeightInPixels(aIndex); + iCurrentDragPos=line2.iTl.iY=line2.iBr.iY=line1.iTl.iY+widthOrHeight; + } + if(iDragDim!=ENoDrag) + { + TArrows arrows=(widthOrHeight==0? ESecondArrowOnly : EBothArrows); + DrawArrowsToInMemoryBitmap(arrows); + TRect invalid = TRect(line1.iTl,line2.iBr); + if(iDragDim==EXDrag) + { + invalid.iTl.iX-=2; + invalid.iBr.iX+=KArrowLength+KArrowSeparation; + } + else + { + invalid.iTl.iY-=2; + invalid.iBr.iY+=KArrowLength+KArrowSeparation; + } + iWin->Invalidate(invalid); + iDrawResizeLines=ETrue; + return ETrue; + } + else + return EFalse; + } + +void CGridImg::DrawResizingDragHiglights(const TRect& aRect) + { + if(iDrawResizeLines) + { + TRect line1 = iGridRect; + TRect line2 = iGridRect; + if(iDragDim==EXDrag) + { + line1.iTl.iX=line1.iBr.iX=iGridLay->ColumnToXVal(iDragLabel)-1; + line2.iTl.iX=line2.iBr.iX=iCurrentDragPos; + } + else if(iDragDim==EYDrag) + { + line1.iTl.iY=line1.iBr.iY=iGridLay->RowToYVal(iDragLabel)-1; + line2.iTl.iY=line2.iBr.iY=iCurrentDragPos; + } + CreateGc(iGc); + TRect clip=aRect; + clip.Intersection(iGridRect); + iGc->SetClippingRect(clip); + DrawDraggingHighlight(line1,EDragDrawWithoutBitmap); + DrawDraggingHighlight(line2,EDragDrawWithBitmap); + DeleteGc(); + } + } + +EXPORT_C TBool CGridImg::UpdateLabelResize(TInt aDelta) +/** Changes the size of the row or column currently being resized. + +@param aDelta The amount, in pixels, by which the size of the row or column +is being changed. +@return True, if a row or column is being resized; false, otherwise. */ + { + if(iDragDim==ENoDrag) + return EFalse; + TRect line1 = iGridRect; + TRect line2 = iGridRect; + if (iDragDim == EXDrag) + { + TInt left=iGridLay->ColumnToXVal(iDragLabel); + line1.iTl.iX = line1.iBr.iX = iCurrentDragPos; + line2.iTl.iX = line2.iBr.iX = iCurrentDragPos = + Max(left,Min(iCurrentDragPos+aDelta,iGridRect.iBr.iX)); + } + else + { + TInt top=iGridLay->RowToYVal(iDragLabel); + line1.iTl.iY = line1.iBr.iY = iCurrentDragPos; + line2.iTl.iY = line2.iBr.iY = iCurrentDragPos = + Max(top,Min(iCurrentDragPos+aDelta,iGridRect.iBr.iY)); + } + if (line1!=line2) + { + CreateGc(iGc); + iGc->SetClippingRect(iGridRect); + DrawDraggingHighlight(line1,EDragDrawWithBitmap); + DrawDraggingHighlight(line2,EDragDrawWithBitmap); + DeleteGc(); + } + return ETrue; + } + +EXPORT_C void CGridImg::FinishLabelResizeL(TBool aResize) +/** Completes the resizing of a row or column. + +@param aResize ETrue, to complete the resizing of the row or column; EFalse, +if the row or column is to retain its original size. */ + { + iDrawResizeLines=EFalse; + if(iDragDim!=ENoDrag && aResize) + { + FinishLabelDragL(); + } + else if (iDragDim!=ENoDrag && !aResize) + { + TRect line1 = iGridRect; + TRect line2 = iGridRect; + if (iDragDim == EXDrag) + { + line1.iTl.iX = line1.iBr.iX = iCurrentDragPos; + line2.iTl.iX = line2.iBr.iX = iGridLay->ColumnToXVal(iDragLabel)-1; + } + else + { + line1.iTl.iY = line1.iBr.iY = iCurrentDragPos; + line2.iTl.iY = line2.iBr.iY = iGridLay->RowToYVal(iDragLabel)-1; + } + CreateGc(iGc); + iGc->SetClippingRect(iGridRect); + DrawDraggingHighlight(line1,EDragDrawWithBitmap); + DrawDraggingHighlight(line2,EDragDrawWithoutBitmap); + DeleteGc(); + } + } + +EXPORT_C TBool CGridImg::StartLabelDrag(const TPoint& aPoint) +/** Deals with the start of a drag operation. + +Typically, the function is called whan handling a pointer event in a control. + +The function checks that the pointer event is within 10 pixels of the boundary +between label cells, and draws a dotted line along the row or column boundary +together with pairs of arrows on either side of that line, and prepares for +the continuation or end of a drag operation on the boundary separating a row +or a column (to expand or contract that row or column). + +The dotted line is a visual indication that a drag operation is in progress. + +@param aPoint The position of the pointer event. +@return True, if the pointer event marks the start of a drag operation, and +dragging is permitted; false otherwise. */ + { + TBool action = EFalse; + TRect line1 = iGridRect; + TRect line2 = iGridRect; + TRangeRef titleRange=iGridLay->TitleRange(); + TRangeRef visibleRange=iGridLay->VisibleRange(); + TArrows arrows = EBothArrows; + if (aPoint.iYIsTopLabelDragDisabled()) + { + TInt previous = iTitlePoint.iX-1; + TInt current=0; + if (iGridLay->IsVerticalTitleLine()) + action = ScanColumnsForDrag(titleRange.iFrom.iCol,titleRange.iTo.iCol,aPoint.iX,previous,current); + if (!action) + action = ScanColumnsForDrag(visibleRange.iFrom.iCol,visibleRange.iTo.iCol,aPoint.iX,previous,current); + if (action) + { + line1.iTl.iX = line1.iBr.iX = previous; + line2.iTl.iX = line2.iBr.iX = iCurrentDragPos = current; + if (previous==current) + arrows=ESecondArrowOnly; + iDragDiff = aPoint.iX - current; + iDragDim = EXDrag; + } + } + else if (aPoint.iXIsSideLabelDragDisabled()) + { + TInt previous = iTitlePoint.iY-1; + TInt current=0; + if (iGridLay->IsHorizontalTitleLine()) + action = ScanRowsForDrag(titleRange.iFrom.iRow,titleRange.iTo.iRow,aPoint.iY,previous,current); + if (!action) + action = ScanRowsForDrag(visibleRange.iFrom.iRow,visibleRange.iTo.iRow,aPoint.iY,previous,current); + if (action) + { + line1.iTl.iY = line1.iBr.iY = previous; + line2.iTl.iY = line2.iBr.iY = iCurrentDragPos = current; + if (previous==current) + arrows=ESecondArrowOnly; + iDragDiff = aPoint.iY - current; + iDragDim = EYDrag; + } + } + if (action) + { + DrawArrowsToInMemoryBitmap(arrows); + CreateGc(iGc); + iGc->SetClippingRect(iGridRect); + DrawDraggingHighlight(line1,EDragDrawWithoutBitmap); + DrawDraggingHighlight(line2,EDragDrawWithBitmap); + DeleteGc(); + } + return action; + } + +const TInt KDragFactor = 5; +const TInt KMaxPenToLabel = 10; +const TInt KMinDraggingLength = 10; + +TBool CGridImg::ScanColumnsForDrag(TInt aFromColumn,TInt aToColumn,TInt aPointerPos,TInt& aPrevious,TInt& aCurrent) + { + TInt ii=aFromColumn; + if (!iGridLay->ColumnWidthInPixels(ii-1)) + --ii; + TInt width=iGridLay->ColumnWidthInPixels(ii++); + aCurrent=aPrevious+width; + TInt currentPenToLabel=(width>=KMinDraggingLength) ? Min(width/KDragFactor,(TInt)KMaxPenToLabel) : 0; + for (;ii<=aToColumn && aCurrentStepColumnForward(ii); + width=iGridLay->ColumnWidthInPixels(ii); + TInt next=aCurrent+width; + TInt nextPenToLabel=(width>=KMinDraggingLength) ? Min(width/KDragFactor,(TInt)KMaxPenToLabel) : 0; + if (aPointerPos>aCurrent-currentPenToLabel && aPointerPos>Min(aPrevious+currentPenToLabel,aCurrent-1) + && aPointerPosStepColumnBackward(iDragLabel); + else if (iGridLay->ColumnWidthInPixels(iDragLabel)==0) + aPrevious=aCurrent; // reopen zero width column + return ETrue; + } + aPrevious=aCurrent; + aCurrent=next; + currentPenToLabel=nextPenToLabel; + } + return EFalse; + } + +TBool CGridImg::ScanRowsForDrag(TInt aFromRow,TInt aToRow,TInt aPointerPos,TInt& aPrevious,TInt& aCurrent) + { + TInt ii=aFromRow; + if (!iGridLay->RowHeightInPixels(ii-1)) + --ii; + TInt height=iGridLay->RowHeightInPixels(ii++); + aCurrent=aPrevious+height; + TInt currentPenToLabel=(height>=KMinDraggingLength) ? Min(height/KDragFactor,(TInt)KMaxPenToLabel) : 0; + for (;ii<=aToRow && aCurrentStepRowForward(ii); + height=iGridLay->RowHeightInPixels(ii); + TInt next=aCurrent+height; + TInt nextPenToLabel=(height>=KMinDraggingLength) ? Min(height/KDragFactor,(TInt)KMaxPenToLabel) : 0; + if (aPointerPos>aCurrent-currentPenToLabel && aPointerPos>Min(aPrevious+currentPenToLabel,aCurrent-1) + && aPointerPosStepRowBackward(iDragLabel); + else if (iGridLay->RowHeightInPixels(iDragLabel)==0) + aPrevious=aCurrent; // reopen zero height row + return ETrue; + } + aPrevious=aCurrent; + aCurrent=next; + currentPenToLabel=nextPenToLabel; + } + return EFalse; + } + +EXPORT_C TBool CGridImg::UpdateLabelDrag(const TPoint& aPoint) +/** Deletes the dotted drag line and and redraws it at the new pointer position. + +Typically, the function is called whan handling a pointer event in a control. + +@param aPoint The position of the pointer event. +@return True, if a drag operation was in progress; false, otherwise. */ + { + if (iDragDim == ENoDrag) + return EFalse; + TRect line1 = iGridRect; + TRect line2 = iGridRect; + if (iDragDim == EXDrag) + { + line1.iTl.iX = line1.iBr.iX = iCurrentDragPos; + line2.iTl.iX = line2.iBr.iX = iCurrentDragPos = Min(aPoint.iX-iDragDiff,iGridRect.iBr.iX-1); + } + else + { + line1.iTl.iY = line1.iBr.iY = iCurrentDragPos; + line2.iTl.iY = line2.iBr.iY = iCurrentDragPos = Min(aPoint.iY-iDragDiff,iGridRect.iBr.iY-1); + } + if (line1!=line2) + { + CreateGc(iGc); + iGc->SetClippingRect(iGridRect); + DrawDraggingHighlight(line1,EDragDrawWithBitmap); + DrawDraggingHighlight(line2,EDragDrawWithBitmap); + DeleteGc(); + } + return ETrue; + } + +void CGridImg::DrawArrowsToInMemoryBitmap(TArrows aArrows) + { + const TInt KNoOfPoints = 3; + CFbsBitmapDevice* bmpDevice=NULL; + CGraphicsContext* bmpGc=NULL; + delete iDragBmp; + iDragBmp=NULL; + TRAPD(err, + iDragBmp = new(ELeave) CFbsBitmap; + TSize bmpSize; + if (iDragDim==EXDrag) + bmpSize.SetSize(2*KArrowLength+KArrowSeparation,KArrowBreadth); + else + bmpSize.SetSize(KArrowBreadth,2*KArrowLength+KArrowSeparation); + iDragBmp->Create(bmpSize,EGray2); + bmpDevice = CFbsBitmapDevice::NewL(iDragBmp); + CleanupStack::PushL(bmpDevice); + User::LeaveIfError(bmpDevice->CreateContext(bmpGc)); + CleanupStack::Pop(); // bmpDevice + ); + if (err!=KErrNone) + { + delete iDragBmp; + iDragBmp=NULL; + return; // No big deal - we just don't draw the arrows in low memory conditions + } + bmpGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + bmpGc->SetBrushColor(KRgbBlack); + TPoint arrow[KNoOfPoints]; + if (iDragDim==EXDrag) + { + if (aArrows==EBothArrows) + { + arrow[0].SetXY(KArrowLength-1,0); + arrow[1].SetXY(KArrowLength-1,KArrowBreadth-1); + arrow[2].SetXY(0,KArrowBreadth/2); + bmpGc->DrawPolygon(arrow,KNoOfPoints); + } + arrow[0].SetXY(KArrowLength+KArrowSeparation,0); + arrow[1].SetXY(arrow[0].iX,KArrowBreadth-1); + arrow[2].SetXY(arrow[1].iX+KArrowLength,KArrowBreadth/2); + bmpGc->DrawPolygon(arrow,KNoOfPoints); + } + else + { + if (aArrows==EBothArrows) + { + arrow[0].SetXY(KArrowBreadth/2,0); + arrow[1].SetXY(0,KArrowLength-1); + arrow[2].SetXY(KArrowBreadth-1,KArrowLength-1); + bmpGc->DrawPolygon(arrow,KNoOfPoints); + } + arrow[0].SetXY(0,KArrowLength+KArrowSeparation); + arrow[1].SetXY(KArrowBreadth-1,arrow[0].iY); + arrow[2].SetXY(KArrowBreadth/2,arrow[1].iY+KArrowLength); + bmpGc->DrawPolygon(arrow,KNoOfPoints); + } + delete bmpGc; + delete bmpDevice; + } + +void CGridImg::DrawDraggingHighlight(const TRect aLine,TDragDraw aDragDraw) + { + __ASSERT_DEBUG(iGcPtr==iGc,Panic(EGridImgInvalidGC)); // Can only call this using internal GC + iGc->SetDrawMode(CGraphicsContext::EDrawModeNOTXOR); + iGc->SetPenStyle(CGraphicsContext::EDottedPen); + iGc->DrawLine(aLine.iTl,aLine.iBr); + if (aDragDraw==EDragDrawWithoutBitmap || !iDragBmp) + return; + + const TInt KNoOfArrowsToDisplay = 4; + const TInt KMinArrowSeparation = 25; + TSize bmpSize=iDragBmp->SizeInPixels(); + if (iDragDim==EXDrag) + { + TInt separation=Max((aLine.iBr.iY-iTitlePoint.iY)/KNoOfArrowsToDisplay,KMinArrowSeparation); + TPoint point(aLine.iTl.iX-bmpSize.iWidth/2,iTitlePoint.iY+(separation-bmpSize.iHeight)/2); + while (point.iYBitBlt(point,iDragBmp); + point.iY+=separation; + } + } + else + { + TInt separation=Max((aLine.iBr.iX-iTitlePoint.iX)/KNoOfArrowsToDisplay,KMinArrowSeparation); + TPoint point(iTitlePoint.iX+(separation-bmpSize.iWidth)/2,aLine.iTl.iY-bmpSize.iHeight/2); + while (point.iXBitBlt(point,iDragBmp); + point.iX+=separation; + } + } + } + +EXPORT_C void CGridImg::ScrollL(const TPoint &aOffset) +/** Scrolls the grid by the specified number of pixels. + +Draws the minimum necessary, i.e. grid labels, grid lines, grid cells, selected +regions and the cursor. + +@param aOffset Scroll offset, in pixels. */ + { + if (!aOffset.iY && !aOffset.iX) + return; + TRect scrollRect; + TRect validRect; + TRegionFix<4> region; + if (aOffset.iX) + { + scrollRect=iGridRect; + scrollRect.iTl.iX=iMainPoint.iX; + validRect=scrollRect; + if (aOffset.iX>0) + validRect.iBr.iX = Min(validRect.iBr.iX,validRect.iTl.iX+aOffset.iX); + else + validRect.iTl.iX = Max(validRect.iTl.iX,validRect.iBr.iX+aOffset.iX); + iWin->Scroll(scrollRect, TPoint(aOffset.iX,0)); + region.AddRect(validRect); + } + if (aOffset.iY) + { + scrollRect=iGridRect; + scrollRect.iTl.iY=iMainPoint.iY; + validRect=scrollRect; + if (aOffset.iY>0) + validRect.iBr.iY = Min(validRect.iBr.iY,validRect.iTl.iY+aOffset.iY); + else + validRect.iTl.iY = Max(validRect.iTl.iY,validRect.iBr.iY+aOffset.iY); + iWin->Scroll(scrollRect, TPoint(0,aOffset.iY)); + region.AddRect(validRect); + } + region.Tidy(); + TInt end=region.Count(); + for (TInt ii=0;iiIsPrintedLabels()) + { + if (iGridLay->IsSideLabels()) + iTitlePoint.iX+=MaxSideLabelWidthInPixels(); + if (iGridLay->IsTopLabels()) + iTitlePoint.iY+=TopLabelHeightInPixels(); + } + iMainPoint=iTitlePoint; + } + +EXPORT_C void CGridImg::ResetReferencePoints() +/** Resets the reference points. + +The reference points are the mainpoint and the titlepoint, i.e the point at +which the visible range starts, and the point at the top left of the grid +not including the labels. */ + { + iTitlePoint=iGridRect.iTl; + if (iGridLay->IsSideLabels()) + iTitlePoint.iX+=SideLabelWidthInPixels(); + if (iGridLay->IsTopLabels()) + iTitlePoint.iY+=TopLabelHeightInPixels(); + iMainPoint=iTitlePoint+iGridLay->TopLeftTitleRangeSize(); + } + +EXPORT_C void CGridImg::NotifyGridRangeResize() +/** Resets the region boundary to the grid boundary. */ + { + iGridLay->LimitCell(iCursorPos); + iGridLay->LimitCell(iAnchorPos); + iSelected->ResizeBounds(iGridLay->iGridRange.iTo); + } + +//-> +EXPORT_C void CGridImg::SetGridLabelImg(CGridLabelImg* aGridLabelImg) +/** Sets an object that draws a cell label. + +@param aGridLabelImg A pointer to an object that draws a cell label. */ + { + iGridLabelImg = aGridLabelImg; + if (aGridLabelImg && iGridLay) + aGridLabelImg->SetGridColors(iGridLay->GridColors()); + } + +void CGridImg::SetGridColors(const TGridColors& aGridColors) + { + iGridLabelImg->SetGridColors(aGridColors); + iGridCellImg->SetGridColors(aGridColors); + } +//->