// ZOOM.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikmenu.hrh>
#include <eikcmds.hrh>
#include <eikdialg.h>
#include <coecntrl.h>
#include <eikappui.h>
#include <eikdoc.h>
#include <eikenv.h>
#include <eikdef.h>
#include <eikapp.h>
#include <eikmover.h>
#include <eikrubtl.h>
#include <badesca.h>
#include <basched.h>
#include <barsread.h>
#include <e32hal.h>
#include <e32std.h>
#include <e32base.h>
#include <frmframe.h>
#include <eikcfdlg.h>
#include <eikon.rsg>

#include "zoom.hrh"
#include "zoom.h"
#include <zoom.rsg>

#define KZoomDefaultPath _L("C:\\")


/////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomAreaSprite
//
// A sprite in the form of a rectangle outline, intended to show the area being zoomed
// into by the CZoomWindow class. The position and size of the sprite can be changed.
// The sprite moves over a window of the size of the screen.
//

CZoomAreaSprite::CZoomAreaSprite(RWsSession& aWs) : iSprite(aWs)
//
// Constructor
//
	{
	}

CZoomAreaSprite::~CZoomAreaSprite()
//
// Destructor. Free the sprite and sprite bitmap.
//
	{
	iSprite.Close();
	delete iBitmap;
	}

void CZoomAreaSprite::ConstructL(TRect& aRect)
//
// Construct the sprite and window over which the sprite moves.
//
	{
	// create window the size of the screen over which the sprite can move
	CreateWindowL();
	Window().SetShadowDisabled(ETrue);
	Window().SetOrdinalPosition(KMaxTInt);
	SetExtentToWholeScreenL();	
	
	// create bitmap for sprite
	iBitmap=new (ELeave) CFbsBitmap;

	// create sprite given the bitmap we just created
	TSpriteMember sprite;
	sprite.iBitmap=iBitmap;
	sprite.iMaskBitmap=iBitmap;
	sprite.iInvertMask=ETrue;
	sprite.iInterval=0;
	User::LeaveIfError(iSprite.Construct(*DrawableWindow(), Rect().iTl, 0/*flags*/));
	User::LeaveIfError(iSprite.AppendMember(sprite));

	// set dimensions and positions of sprite
	SetSpriteRectL(aRect);

	// activate sprite
	iSprite.Activate();
	}

void CZoomAreaSprite::SetSpritePosition(TPoint aPos)
//
// Move the sprite
//
	{
	iSprite.SetPosition(aPos);
	}

void CZoomAreaSprite::SetSpriteRectL(TRect& aRect)
//
// Set dimensions and position of sprite.
//
	{
	// (re)create bitmap for sprite. bitmap will be cleared
	User::LeaveIfError(iBitmap->Create(aRect.Size(), EGray2));

	// create bitmap device and context to be able to draw in sprite bitmap
	CFbsBitmapDevice *bitmapDev=CFbsBitmapDevice::NewL(iBitmap);
	CFbsBitGc *bitmapGc;
	bitmapDev->CreateContext(bitmapGc);

	// draw a outline rectangle in the sprite bitmap
	bitmapGc->DrawRect(TRect(TPoint(0,0), aRect.Size()));

	// move the sprite
	iSprite.SetPosition(aRect.iTl);

	// tell the sprite its bitmap is updated
	TSpriteMember sprite;
	sprite.iBitmap=iBitmap;
	sprite.iMaskBitmap=iBitmap;
	sprite.iInvertMask=ETrue;
	sprite.iInterval=0;
	iSprite.UpdateMember(0,sprite);

	// get rid off the bitmap device
	delete bitmapGc;
	delete bitmapDev;
	}

/////////////////////////////////////////////////////////////////////////////////////
//
// Class CZoomNukeAppUi
//  
// A "Nuke" button that fires the AppUi exit function
// 

CZoomNukeAppUi::CZoomNukeAppUi(CZoomAppUi* anAppUi)
	: iControllingAppUi(anAppUi)
	{
	__DECLARE_NAME(_S("CZoomNukeAppUi"));
	SetNonFocusing();
	}

void CZoomNukeAppUi::Draw(const TRect& /*aRect*/) const
	{
	CWindowGc& gc=SystemGc();

	// draws the surrounding box
	TRect rect=Rect();
	gc.DrawRect(rect);
	gc.DrawLineBy(TPoint(rect.Size().iWidth,-rect.Size().iHeight));
	gc.MoveBy(TPoint(0,rect.Size().iHeight));
	gc.DrawLineBy(TPoint(-rect.Size().iWidth,-rect.Size().iHeight));
	}

void CZoomNukeAppUi::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	if (aPointerEvent.iType == TPointerEvent::EButton1Down)
		iControllingAppUi->ZoomExit();
	}


/////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomCorner
// 
// A sprite to indicate the bottom right hand corner of the window 
// to give users an impression of what resizing is allowed
//
//

CZoomCorner::CZoomCorner(RWsSession& aWs)
	: iSprite(aWs)
	{
	}

CZoomCorner::~CZoomCorner()
//
// Destructor. Free the sprite and sprite bitmap.
//
	{
	iSprite.Close();
	delete iBitmap;
	}

void CZoomCorner::ConstructL(TRect& aRect)
//
// Construct the sprite and window over which the sprite moves.
//
	{
	// create window the size of the screen over which the sprite can move
	CreateWindowL();
	Window().SetShadowDisabled(ETrue);
	Window().SetOrdinalPosition(KMaxTInt);
	SetExtentToWholeScreenL();	
	
	// create bitmap for sprite
	iBitmap=new (ELeave) CFbsBitmap;

	// create sprite given the bitmap we just created
	TSpriteMember sprite;
	sprite.iBitmap=iBitmap;
	sprite.iMaskBitmap=iBitmap;
	sprite.iInvertMask=ETrue;
	sprite.iInterval=0;
	User::LeaveIfError(iSprite.Construct(*DrawableWindow(), Rect().iTl, 0/*flags*/));
	User::LeaveIfError(iSprite.AppendMember(sprite));

	// set dimensions and positions of sprite
	SetSpriteRectL(aRect);

	// activate sprite
	iSprite.Activate();
	}

void CZoomCorner::SetSpritePosition(TPoint aPos)
//
// Move the sprite
//
	{
	iSprite.SetPosition(aPos);
	}

void CZoomCorner::SetSpriteRectL(TRect& aRect)
//
// Set dimensions and position of sprite.
//
	{
	// (re)create bitmap for sprite. bitmap will be cleared
	User::LeaveIfError(iBitmap->Create(aRect.Size(), EGray2));

	// create bitmap device and context to be able to draw in sprite bitmap
	CFbsBitmapDevice *bitmapDev=CFbsBitmapDevice::NewL(iBitmap);
	CFbsBitGc *bitmapGc;
	bitmapDev->CreateContext(bitmapGc);

	// draw bottom and right lines to the sprite bitmap
	TSize size = aRect.Size();
	bitmapGc->MoveBy(TPoint(0, size.iHeight - 1));
	bitmapGc->DrawLineBy(TPoint(size.iWidth - 1,0));
	bitmapGc->DrawLineBy(TPoint(0, -size.iHeight));

	// move the sprite
	iSprite.SetPosition(aRect.iTl);

	// tell the sprite its bitmap is updated
	TSpriteMember sprite;
	sprite.iBitmap=iBitmap;
	sprite.iMaskBitmap=iBitmap;
	sprite.iInvertMask=ETrue;
	sprite.iInterval=0;
	iSprite.UpdateMember(0,sprite);

	// get rid off the bitmap device
	delete bitmapGc;
	delete bitmapDev;
	}



/////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomResizer
//
// "Button" to allow drag and drop resizing of the window
//
//

CZoomResizer::CZoomResizer(CZoomControl* aParent)
	: iParent(aParent)
	{
	__DECLARE_NAME(_S("CZoomResizer"));
	SetNonFocusing();
	}

CZoomResizer::~CZoomResizer()
	{
	delete iCorner;  //  In case the destructor is called due to a leave during sprite movement
	}

TInt CZoomResizer::CountComponentControls() const
	{
	return (iCorner) ? 1 : 0;
	}

CCoeControl* CZoomResizer::ComponentControl(TInt /*aIndex*/) const
	{
	return (iCorner) ? iCorner : 0;
	}

void CZoomResizer::Draw(const TRect& /*aRect*/) const
	{
	CWindowGc& gc=SystemGc();

	// draws the surrounding box
	TRect rect=Rect();
	gc.DrawRect(rect);
	}

void CZoomResizer::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	switch (aPointerEvent.iType)
		{
		case TPointerEvent::EButton1Down:
			CreateZoomCornerL();
			break;

		case TPointerEvent::EButton1Up:
			{
			TSize newSize(aPointerEvent.iPosition.iX, aPointerEvent.iPosition.iY);
			TSize minSize = iParent->MinimumSize();
			if (newSize.iWidth < minSize.iWidth)
				newSize.iWidth = minSize.iWidth;
			if (newSize.iHeight < minSize.iHeight)
				newSize.iHeight = minSize.iHeight;
			iParent->SetSizeL(newSize);
			DeleteZoomCorner();
			break;
			}

		case TPointerEvent::EDrag:
			iCorner->SetSpritePosition(aPointerEvent.iParentPosition);
			break;

		default:
			break;
		}
	}

void CZoomResizer::CreateZoomCornerL()
//
// Creates the corner indicator sprite based upon the size of the resizer
//
	{
	TRect rect = Rect();
	iCorner = new (ELeave) CZoomCorner(ControlEnv()->WsSession());
	iCorner->ConstructL(rect);
	iCorner->ActivateL();			
	}

void CZoomResizer::DeleteZoomCorner()
//
// Deletes the corner indicator sprite
//
	{
	delete iCorner;
	iCorner=NULL;
	}


/////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomWindow
//
// The window which displays the zoom-in-area. Includes all the code for getting
// the pointer events, updating the zoom-in-area indicator, and the grabbing and
// displaying of the bitmap.
//

CZoomWindow::CZoomWindow()
//
// Constructor
//
	{
	__DECLARE_NAME(_S("CZoomWindow"));
	SetNonFocusing();

	// set defaults for bitmapsize, zoomfactor and centre
	iBitmapSize.SetSize(EBitmapWidth,EBitmapHeight);
	iZoomFactor=EDefaultZoomFactor;
	iZoomCentre=TPoint(ZoomSize().iWidth,ZoomSize().iHeight);
	}

CZoomWindow::~CZoomWindow()
//
// Destructor
//
    {
	delete iZoomAreaSprite;
	delete iBitmap;
	}

void CZoomWindow::ConstructL()
//
// Construct bitmap for displaying zoomed area
//
	{
	iBitmap=new (ELeave) CFbsBitmap;
	User::LeaveIfError(iBitmap->Create(iBitmapSize,EGray4));
	UpdateZoomAreaBitmap();
	}


void CZoomWindow::SetActive(TBool aActive)
//
// Activates the pointer grab flag
//
	{
	iActive = aActive;
	}

inline TBool CZoomWindow::Active() const
//
// Returns the active flag
//
	{
	return iActive;
	}


TSize CZoomWindow::MinimumSize()
//
// Minimum size of component
//
    {
	// Minimum size is the 1-pixel outline of the window.
	return TSize(1,1);
    }

void CZoomWindow::SizeChangedL()
//
// Resets the size of the zoom window for a changed window size
//
	{
   	// resize bitmap and keep in mind (1,1) border.
	iBitmapSize=iSize-TSize(1,1);
	iBitmap->Resize(iBitmapSize);

	TPoint zoomCentre = ZoomCentre();
	// Check that the window is still within the screen boundaries
	if(!SetZoomCentre(zoomCentre))
		{
		TPoint newZoomCentre = zoomCentre;
		TSize zoomSize = ZoomSize();
		TSize screenSize = iEikonEnv->ScreenDevice()->SizeInPixels();
		if((zoomCentre.iX - zoomSize.iWidth/2) < 0) newZoomCentre.iX = (zoomSize.iWidth + 1)/2;
		else
			{
			if((zoomCentre.iX + zoomSize.iWidth/2) > (screenSize.iWidth - 1))
				newZoomCentre.iX = (screenSize.iWidth - 1) - (zoomSize.iWidth + 1)/2;
			}
		if((zoomCentre.iY - zoomSize.iHeight/2) < 0) newZoomCentre.iY = (zoomSize.iHeight + 1)/2;
		else
			{
			if((zoomCentre.iY + zoomSize.iHeight/2) > (screenSize.iHeight - 1))
				newZoomCentre.iY = (screenSize.iHeight - 1) - (zoomSize.iHeight + 1)/2;
			}

		SetZoomCentre(newZoomCentre);
		}
	UpdateNow();
	}

void CZoomWindow::UpdateNow()
	{
	// update bitmap and sprite
	UpdateZoomAreaBitmap();
	UpdateZoomAreaSprite();

	DrawNow();
	}


TSize CZoomWindow::ZoomSize() const
//
// Returns the number of pixels that are displayed in the zoom window
// at the current zoom level.
//
	{
	TSize zoomSize=iBitmapSize;
	zoomSize.iWidth=(zoomSize.iWidth*1000)/iZoomFactor;
	zoomSize.iHeight=(zoomSize.iHeight*1000)/iZoomFactor;
	return zoomSize;
	}

TBool CZoomWindow::SetZoomCentre(TPoint aCentre)
//
// Set centre point of the zoom area on the screen and copies the area from
// the screen at that point.
//
// Change of interface from:
// Returns EFalse when centre point is not on the screen, ETrue otherwise.
//
// to:
// Returns EFalse when the zoom window would contain any area that is not on
// the screen
	{
		TBool contains;

		TRect screenRect(TPoint(0,0), iEikonEnv->ScreenDevice()->SizeInPixels());
		if ( (screenRect.Contains(aCentre + TPoint((ZoomSize().iWidth + 1)/2,(ZoomSize().iHeight + 1)/2 ))) &&
				(screenRect.Contains(aCentre - TPoint((ZoomSize().iWidth + 1)/2,(ZoomSize().iHeight + 1)/2))) )
			{
			iZoomCentre = aCentre;
			UpdateZoomAreaSprite();
			contains = ETrue;
			}
		else
			contains=EFalse;

		UpdateZoomAreaBitmap();
		return contains;
}

TPoint CZoomWindow::ZoomCentre() const
//
// Return the centre point of the zoom area on the screen
//
	{
		return iZoomCentre;
	}

void CZoomWindow::SetZoomFactor(TInt aFactor)
//
// Sets the zoom level (EZoomOneToOne = 1000).
// aFactor > EZoomOneToOne scales up
// aFactor < EZoomOneToOne scales down
//
	{
	if (aFactor > 0)
		{
		iZoomFactor = aFactor;
		UpdateZoomAreaSprite();
		SizeChangedL();
		}
	}

TInt CZoomWindow::ZoomFactor() const
//
// Returns the zoom level
//
	{
	return iZoomFactor;
	}

void CZoomWindow::Draw(const TRect& /* aRect */) const
//
// Draws the window
//
    {
	CWindowGc& gc=SystemGc();

	// draws the surrounding box
	TRect rect=Rect();
	gc.DrawRect(rect);

	// display the bitmap zoomed
	TRect theZoomRect;
	ZoomRect(theZoomRect);
	rect.Shrink(1,1); // shrink for border
	gc.DrawBitmap(rect, iBitmap, TRect(TPoint(0,0), theZoomRect.Size()));
	}

void CZoomWindow::HandlePointerEventL(const TPointerEvent& aPointerEvent)
//
// Captures the pointer events to indicate the area of screen to be zoomed in on.
// An indicator moves along with the pointer position to show the extent of the
// area being zoomed.
//
	{
	if (!Active())
		return;
	
	if (aPointerEvent.iType==TPointerEvent::EButton1Up)
		{
		SetZoomCentre(aPointerEvent.iParentPosition);
		DrawNow();
		DeleteZoomAreaSprite();
		}
	else if (aPointerEvent.iType==TPointerEvent::EButton1Down)
		{
		SetZoomCentre(aPointerEvent.iParentPosition);
		CreateZoomAreaSpriteL();
		DrawNow();
		}
	else if (aPointerEvent.iType==TPointerEvent::EDrag)
		{
		SetZoomCentre(aPointerEvent.iParentPosition);
		UpdateZoomAreaSprite();
		DrawNow();
		}
    }

void CZoomWindow::ZoomRect(TRect &aRect) const
//
// Calculates the zoom rectangle on the screen based on the zoom
// centre point and the size of the zooming window.
//
	{
	TSize zoomSize=iBitmapSize;
	zoomSize.iWidth=(zoomSize.iWidth*1000)/iZoomFactor;
	zoomSize.iHeight=(zoomSize.iHeight*1000)/iZoomFactor;

	aRect.iTl=TPoint(iZoomCentre.iX-zoomSize.iWidth/2, 
		             iZoomCentre.iY-zoomSize.iHeight/2);

	aRect.SetSize(zoomSize);
	}

TBool CZoomWindow::ZoomRectInsideScreen(TRect &aRect) const
//
// Report to caller if zoom rectangle was not contained within screen
//
	{
	TRect screenRect(TPoint(0,0), iEikonEnv->ScreenDevice()->SizeInPixels());
	if (!screenRect.Contains(aRect.iTl) ||
		!screenRect.Contains(aRect.iBr))
		return(EFalse);
	else
		return(ETrue);
	}

void CZoomWindow::UpdateZoomAreaBitmap()
//
// Update the bitmap copied from the screen. This is the bitmap which we use for zooming.
//
	{
	// draws the bitmap in the box
	TRect theZoomRect;
	ZoomRect(theZoomRect);

	// when the zoom-in-area is not totally contained within the screen, the 
	// 'CopyScreenToBitmap' will only partially update the destination bitmap.
	// By creating it again, the bitmap is cleared and not updated pixels will be white.
	if (!ZoomRectInsideScreen(theZoomRect))
		{
		iBitmap->Reset(); // !! necessary ?
		iBitmap->Create(iBitmapSize,EGray4);
		}

	// copy the zoom-in-area to a bitmap
	iEikonEnv->ScreenDevice()->CopyScreenToBitmap(iBitmap,theZoomRect);		
	}

void CZoomWindow::CreateZoomAreaSpriteL()
//
// Creates the zoom area indicator sprite based on the current zoom centre and factor
//
	{
	iZoomAreaSprite = new (ELeave) CZoomAreaSprite(ControlEnv()->WsSession());
	TRect screenZoomRect;
	ZoomRect(screenZoomRect);
	iZoomAreaSprite->ConstructL(screenZoomRect);
	iZoomAreaSprite->ActivateL();			
	}

void CZoomWindow::DeleteZoomAreaSprite()
//
// Deletes the zoom area indicator sprite
//
	{
	delete iZoomAreaSprite;
	iZoomAreaSprite=NULL;
	}

void CZoomWindow::UpdateZoomAreaSprite() const
//
// Updates (position,size) the zoom area indicator sprite based on the
// current zoom centre and factor.
//
	{
	if (iZoomAreaSprite)
		{
		TRect rect;
		ZoomRect(rect);
		iZoomAreaSprite->SetSpriteRectL(rect);
		}
	}

void CZoomWindow::ZoomSaveBitmap(TFileName& aFilename)
	{
	User::LeaveIfError(iBitmap->Save(aFilename));
	}

/////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomControl
//
// The control class for the CZoomWindow.
//
// Certain keys (eg. page up) are implemented to have some control over the
// CZoomWindow object.
//

CZoomControl::CZoomControl(CZoomAppUi* anAppUi)
	: iParentAppUi(anAppUi)
//
// Constructor
//
	{
	__DECLARE_NAME(_S("CZoomControl"));
	}

CZoomControl::~CZoomControl()
//
// Destructor
//
	{
	delete iMover;
	delete iNuke;
	delete iZoomWindow;
	delete iZoomResizer;
	}

void CZoomControl::ConstructL()
//
// The actual constructor for CZoomControl
//
    {
	// parent window
	CreateWindowL();
	EnableDragEvents();
	Window().SetPointerGrab(ETrue);
	Window().ClaimPointerGrab();
	iEikonEnv->AddWindowShadow(this);

	// moving bar component
	iMover=new(ELeave) CEikMover;
	iMover->SetContainerWindowL(*this);
		{
		TBuf<16> title;
		iEikonEnv->ReadResource(title, R_ZOOM_TITLE);
		iMover->SetTextL(title);
		}
	iMover->SetActive(ETrue);

	iZoomRect.SetRect(	EZoomMargin,
						EZoomMargin+EZoomTitleHeight,
						EZoomMargin+EZoomZoomWidth,
						EZoomMargin+EZoomTitleHeight+EZoomZoomHeight);

	// zoom-in-area component
	iZoomWindow = new (ELeave) CZoomWindow;
	iZoomWindow->ConstructL();
	iZoomWindow->SetContainerWindowL(*this);
	iZoomWindow->SetRectL(iZoomRect);
	iZoomWindow->SetActive(ETrue);

	// resizer component
	iZoomResizer = new (ELeave) CZoomResizer(this);
	iZoomResizer->SetContainerWindowL(*this);
	iZoomResizer->SetRectL(	TRect(EZoomMargin+EZoomZoomWidth,
							EZoomMargin+EZoomTitleHeight+EZoomZoomHeight,
							EZoomWindowWidth-EZoomBorderWidth,
							EZoomWindowHeight-EZoomBorderWidth));

	// nuke component
	iNuke = new (ELeave) CZoomNukeAppUi(iParentAppUi);
	iNuke->SetContainerWindowL(*this);
	iNuke->SetRectL(TRect(	EZoomWindowWidth - EZoomTitleHeight, 0,
							EZoomWindowWidth,EZoomTitleHeight));

	SetExtentL(TPoint(0,0), TSize(EZoomWindowWidth,EZoomWindowHeight)); 

	}


void CZoomControl::SizeChangedL()
//
// Resets the size of the mover for a changed window size
//
	{
	TRect rect=Rect();
	rect.Shrink(1,1);
	rect.iBr.iY = rect.iTl.iY+EZoomTitleHeight;
	rect.iBr.iX -= EZoomTitleHeight;
	iMover->SetRectL(rect);
	rect.iTl.iX = rect.iBr.iX;
	rect.iBr.iX += EZoomTitleHeight;
	iNuke->SetRectL(rect);

	iZoomRect.SetRect(TPoint(EZoomMargin,EZoomMargin+EZoomTitleHeight),
					  TSize(iSize.iWidth-EZoomMargin*2,
					        iSize.iHeight-EZoomMargin*2-EZoomTitleHeight));
	iZoomWindow->SetRectL(iZoomRect);
	iZoomResizer->SetRectL(TRect(iZoomRect.iBr,iZoomRect.iBr+TPoint(EZoomMargin,EZoomMargin)));
	DrawNow();
	}

void CZoomControl::Draw(const TRect& /*aRect*/) const
//
// Draws the CZoomControl window 
//
	{
	TRect rect=Rect();
	CWindowGc& gc=SystemGc();
	gc.Clear();
	gc.DrawRect(rect);
	}


TInt CZoomControl::CountComponentControls() const
//
// Number of components in the window 
//
    {
    return(4);
    }

CCoeControl* CZoomControl::ComponentControl(TInt aIndex) const
//
// Return access to the mover and zoomed-in-area
//
    {			 
	switch (aIndex)
		{
		case 0:
		return iMover;
		
		case 1:
		return iZoomWindow;

		case 2:
		return iZoomResizer;

		default:
		return iNuke;
		}
    }

TSize CZoomControl::MinimumSize()
	{
	return TSize(	EZoomMargin*2 + EZoomMinimumBitmapSize,
					EZoomMargin*2 + EZoomMinimumBitmapSize + EZoomTitleHeight);
	}




TKeyResponse CZoomControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
//
// Response to key event
//
	{
	if (aType!=EEventKey)
		return EKeyWasConsumed;

	switch(aKeyEvent.iCode)
	{

	case EKeyLeftArrow:
		{
		TInt shift;
		shift = (aKeyEvent.iModifiers & EModifierShift) ? -10 : -1;
		if(iZoomWindow->SetZoomCentre(iZoomWindow->ZoomCentre() + TPoint(shift,0)))
		{
			iZoomWindow->DrawNow();
			break;
		}
		}

		// Fall through case if the point wasn't on the screen
	case EKeyHome:
		{
		TPoint centre = iZoomWindow->ZoomCentre();
		centre.iX = iZoomWindow->ZoomSize().iWidth / 2;
		iZoomWindow->SetZoomCentre(centre);
		iZoomWindow->DrawNow();
		}
		break;


	case EKeyRightArrow:
		{
		TInt shift;
		shift = (aKeyEvent.iModifiers & EModifierShift) ? 10 : 1;
		if(iZoomWindow->SetZoomCentre(iZoomWindow->ZoomCentre() + TPoint(shift,0)))
		{
			iZoomWindow->DrawNow();
			break;
		}
		}

		// fall through
	case EKeyEnd:
		{
		TPoint centre = iZoomWindow->ZoomCentre();
		centre.iX = iEikonEnv->ScreenDevice()->SizeInPixels().iWidth - (iZoomWindow->ZoomSize().iWidth + 1) / 2 - 1; // -1 to correct the fact the size starts at 0,0 and finishes at 640,240
		iZoomWindow->SetZoomCentre(centre);
		iZoomWindow->DrawNow();
		}
		break;

	case EKeyUpArrow:
		{
		TInt shift;
		shift = (aKeyEvent.iModifiers & EModifierShift) ? -10 : -1;
		if(iZoomWindow->SetZoomCentre(iZoomWindow->ZoomCentre() + TPoint(0,shift)))
		{
			iZoomWindow->DrawNow();
			break;
		}
		}
		
		// fall through
	case EKeyPageUp:
		{
		if (!iZoomWindow->SetZoomCentre(iZoomWindow->ZoomCentre() +
			                            TPoint(0,-iZoomWindow->ZoomSize().iHeight)))
			{
			TPoint centre = iZoomWindow->ZoomCentre();
			centre.iY = iZoomWindow->ZoomSize().iHeight / 2;
			iZoomWindow->SetZoomCentre(centre);
			}			
		iZoomWindow->DrawNow();
		}
		break;

	case EKeyDownArrow:
		{
		TInt shift;
		shift = (aKeyEvent.iModifiers & EModifierShift) ? 10 : 1;
		if(iZoomWindow->SetZoomCentre(iZoomWindow->ZoomCentre() + TPoint(0,shift)))
		{
			iZoomWindow->DrawNow();
			break;
		}
		}
		
		// fall through
	case EKeyPageDown:
		{
		if (!iZoomWindow->SetZoomCentre(iZoomWindow->ZoomCentre() +
			                            TPoint(0,iZoomWindow->ZoomSize().iHeight)))
			{
			TPoint centre = iZoomWindow->ZoomCentre();
			centre.iY = iEikonEnv->ScreenDevice()->SizeInPixels().iHeight - iZoomWindow->ZoomSize().iHeight / 2;
			iZoomWindow->SetZoomCentre(centre);
			}			
		iZoomWindow->DrawNow();
		}
		break;

	default:
		return EKeyWasNotConsumed;
	}
	
	return EKeyWasConsumed;
	}

//////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomAppUi
//
// Zoom application user interface

const TInt KZoomRefreshPriority = -100;

CZoomAppUi::CZoomAppUi()
	{
	iInterval = 20*100000;
	}

void CZoomAppUi::ConstructL()
    {
    BaseConstructL();
    iZoomControl=new(ELeave) CZoomControl(this);
    iZoomControl->ConstructL();
	iZoomControl->ActivateL();
    AddToStackL(iZoomControl);
	iZoomRefresh = NULL;
    }

CZoomAppUi::~CZoomAppUi()
	{
    delete iZoomControl;
	if(iZoomRefresh != NULL)
		delete iZoomRefresh;
	}

void CZoomAppUi::SetTimerRate(TTimeIntervalMicroSeconds32 anInterval)
	{
	iInterval = anInterval;
	}

inline TTimeIntervalMicroSeconds32 CZoomAppUi::TimerRate() { return iInterval; }

inline TBool CZoomAppUi::RefreshState()
	{
	if(iZoomRefresh == NULL)
		return EFalse;
	else
		return ETrue;
	}

void CZoomAppUi::StartPeriodicL()
	{
	TCallBack cb(RefreshDraw,iZoomControl->ZoomWindow()); // create a callback object
	if(iZoomRefresh == NULL)
		{
		iZoomRefresh = CPeriodic::NewL(KZoomRefreshPriority);
		iZoomRefresh->Start(iInterval,iInterval,cb);
		}
	else
		{
		iZoomRefresh->Cancel();
		iZoomRefresh->Start(iInterval,iInterval,cb);
		}
	}

void CZoomAppUi::StopPeriodic()
	{
	delete iZoomRefresh;
	iZoomRefresh = NULL;
	}

TInt CZoomAppUi::RefreshDraw(TAny* aZoomWindow)
    {
	((CZoomWindow*)aZoomWindow)->UpdateNow();
	return ETrue;
	}


void CZoomAppUi::HandleCommandL(TInt aCommand)
	{
	switch (aCommand)
		{

	case EEikCmdZoomIn:
		ZoomIn();
		break;

	case EEikCmdZoomOut:
		ZoomOut();
		break;

	case EZoomGrowWindow:
		SetWindowSizeL(WindowSize()+TSize(EWindowSizeDelta,EWindowSizeDelta));
		break;

	case EZoomShrinkWindow:
		SetWindowSizeL(WindowSize()-TSize(EWindowSizeDelta,EWindowSizeDelta));
		break;

	case EZoomRefreshRate:
		CmdDlgRateL();
		break;

	case EEikCmdFileSaveAs:
		CmdDlgFileSaveAsL();
		break;

    case EEikCmdExit:
		ZoomExit();
		}
	}

void CZoomAppUi::ZoomIn()
	{
	// zoom in - increase the zoom factor
	iZoomControl->ZoomWindow()->SetZoomFactor(iZoomControl->ZoomWindow()->ZoomFactor() + EZoomFactorDelta);
	iZoomControl->ZoomWindow()->DrawNow();
	}

void CZoomAppUi::ZoomOut()
	{
	// zoom out - decrease the zoom factor
	iZoomControl->ZoomWindow()->SetZoomFactor(iZoomControl->ZoomWindow()->ZoomFactor() - EZoomFactorDelta);
	iZoomControl->ZoomWindow()->DrawNow();
	}

void CZoomAppUi::SetWindowSizeL(TSize aControlSize)
	{
	iZoomControl->SetExtentL(iZoomControl->PositionRelativeToScreen(), aControlSize);
	}

TSize CZoomAppUi::WindowSize()
	{
	return iZoomControl->Size();
	}

void CZoomAppUi::CmdDlgFileSaveAsL()
	{
	TFileName fileName = KZoomDefaultPath;
	CEikDialog* dialog=new(ELeave) CEikFileSaveAsDialog(&fileName,NULL,NULL);
	if (dialog->ExecuteLD(R_EIK_DIALOG_FILE_SAVEAS))
		{
		TEntry entry;
		if (!iEikonEnv->FsSession().Entry(fileName,entry))
			User::LeaveIfError(iEikonEnv->FsSession().Delete(fileName));
		iZoomControl->ZoomWindow()->ZoomSaveBitmap(fileName);
		}

	}

void CZoomAppUi::CmdDlgRateL()
    {
	TBool state = (iZoomRefresh != NULL);
	TInt interval = iInterval.Int()/100000;

    CEikDialog* dialog=new(ELeave) CZoomRateDialog(state, interval);
    dialog->ExecuteLD(R_ZOOM_REFRESH_DIALOG);
	SetTimerRate(interval*100000);
	if(state)
		StartPeriodicL();
	else
		StopPeriodic();
    }

void CZoomAppUi::ZoomExit()
	{
	iCoeEnv->Flush(200000);
    CBaActiveScheduler::Exit();
	}


/////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomDocument
//

CEikAppUi* CZoomDocument::CreateAppUiL()
	{
    return(new(ELeave) CZoomAppUi);
	}

/////////////////////////////////////////////////////////////////////////////////////
//
// class CZoomApplication
//

TUid CZoomApplication::AppDllUid() const
	{
	return(KUidZoomApp);
	}

CApaDocument* CZoomApplication::CreateDocumentL()
	{
	return(new(ELeave) CZoomDocument(*this));
	}


//////////////////////////////////////////////////////////////////////////////
//
// -----> CZoomRateDialog(definition)
//
//////////////////////////////////////////////////////////////////////////////

CZoomRateDialog::CZoomRateDialog(TBool& aState, TInt& anInterval)
	: iState(aState), iInterval(anInterval)
	{
	}

void CZoomRateDialog::PreLayoutDynInitL()
	{
	// Do the default formatting here
	SetCheckBoxState(EZoomDlgRefreshStateCheckBox, (iState) ? CEikButtonBase::ESet: CEikButtonBase::EClear);
	SetNumberEditorValue(EZoomDlgRefreshRate , iInterval);
	SetLineDimmedNow(EZoomDlgRefreshRate, !iState);
	}

TBool CZoomRateDialog::OkToExitL(TInt /*aKeycode*/)
	{
	iInterval = NumberEditorValue(EZoomDlgRefreshRate);
	iState  = (CheckBoxState(EZoomDlgRefreshStateCheckBox)==CEikButtonBase::ESet);
	return ETrue;
	}

void CZoomRateDialog::HandleControlStateChangeL(TInt aControlId)
	{
	if (aControlId == EZoomDlgRefreshStateCheckBox)
		SetLineDimmedNow(EZoomDlgRefreshRate, CheckBoxState(EZoomDlgRefreshStateCheckBox) == CEikButtonBase::EClear);
	}



/////////////////////////////////////////////////////////////////////////////////////
//
// EXPORTed functions
//

EXPORT_C CApaApplication* NewApplication()
	{
	return(new CZoomApplication);
	}

GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}

