mapnavproviderrefapp/src/mnrpmapcontrol.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:31:27 +0100
branchRCL_3
changeset 18 870918037e16
parent 0 522cd55cc3d7
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006 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:  CMnrpMapControl class implementation
*
*/


#include <coemain.h>
#include <aknlists.h>
#include <barsread.h>
#include <aknnotewrappers.h>

#include <bitstd.h>
#include <bitdev.h>

#include <lbsposition.h>

#include "debug.h"

#include "mnrputils.h"
#include "mnrpmapview.h"
#include "mnrpmapcontrol.h"

const TInt KCodeKeyLeft = 0x34;
const TInt KCodeKeyRight = 0x36;
const TInt KCodeKeyUp = 0x32;
const TInt KCodeKeyDown = 0x38;
const TInt KCodeKeyCenter = 0x35;

const TInt KCodeKeySelect = EKeyDevice3;
const TInt KCodeKeySelect2 = 0x13;

const TInt KCodeKeyZoomIn = 42;
const TInt KCodeKeyZoomOut = 35;
const TInt KCodeKeyZoomIn2 = 0x33;
const TInt KCodeKeyZoomOut2 = 0x39;

const TRgb KCursorColor( 255, 255, 255 );
const TRgb KGridTextColor( 0, 0, 0 );
const TRgb KOriginMarkColor( 0, 0, 255 );

const TInt KTextFontHeightInTwips = 100;
const TInt KItemFontHeightInTwips = 120;
const TReal KBorderSizeFactor = 2;

const TInt KCursorMarginSize = 20; // pixels
const TInt KCursorArrowSize = 4; // pixels
const TInt KCursorCircleRadius = 4; // pixels

const TInt KCursorMove = 10; // pixels
const TInt KWindowMove = 20; // pixels
const TReal KJumpFactor = 5;
const TReal KCrawlFactor = 2.0 / KCursorMove;

const TReal KZoomOutRate = 1.5;
const TReal KZoomInRate =  1 / KZoomOutRate;

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
CMnrpMapControl::CMnrpMapControl( CMnrpMapView& aView )
 :  iView( aView )
    {
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
CMnrpMapControl::~CMnrpMapControl()
    {
    delete iModel;
    delete iOffScreenBitmap;
    DestroyFonts();
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
CMnrpMapControl* CMnrpMapControl::NewL( 
    CMnrpMapView& aView,
    const TRect& aRect,
    CMnrpEngine& aEngine )
    {
    CMnrpMapControl* self = new ( ELeave ) CMnrpMapControl( aView );
    CleanupStack::PushL( self );
    self->ConstructL( aRect, aEngine );
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::UpdateModelL( CMnrpMapViewService& aService )
    {
    iModel->UpdateModelL( aService );
    }
    
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::SetSelectionModeL( TBool aSelectionMode ) 
    {
    iSelectionMode = aSelectionMode;
    iAbsoluteCursor = iModel->Center();
    iCursor = iModel->AbsoluteToScreen( iAbsoluteCursor );
    DrawDeferred();
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
TCoordinate CMnrpMapControl::CurrentLocation()
    {
    return iAbsoluteCursor;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::ConstructL( 
    const TRect& aRect,
    CMnrpEngine& aEngine )
    {
    // Create a window for this application view
    CreateWindowL();

    iModel = CMnrpMapModel::NewL( *this, aEngine );

    // Set the windows size
    SetRect( aRect );
    
    iAbsoluteCursor = TCoordinate( 0, 0 );
    iCursor = iModel->AbsoluteToScreen( iAbsoluteCursor );
    
    CreateFonts();
    CreateScreenBufferL( aRect.Size() );

    // Activate the window, which makes it ready to be drawn
    ActivateL();
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
TKeyResponse CMnrpMapControl::OfferKeyEventL(
    const TKeyEvent& aKeyEvent, 
    TEventCode /*aType*/ )
    {
    TKeyResponse response = EKeyWasConsumed;
    
    TInt step = iSelectionMode ? KCursorMove : KWindowMove;
    TBool isShift = aKeyEvent.iModifiers & EModifierShift;
    TReal crawlFactor = isShift ? KCrawlFactor : 1;

    TInt xmove = 0;
    TInt ymove = 0;
    
    TBool redraw = ETrue;

    switch ( aKeyEvent.iCode )
        {
        case EKeyLeftArrow:
            xmove = -step * crawlFactor;
            break;

        case KCodeKeyLeft:
            xmove = -step * KJumpFactor;
            break;

        case EKeyRightArrow:
            xmove = step * crawlFactor;
            break;

        case KCodeKeyRight:
            xmove = step * KJumpFactor;
            break;

        case EKeyUpArrow:
            ymove = -step * crawlFactor;
            break;

        case KCodeKeyUp:
        case EKeyPageUp:
            ymove = -step * KJumpFactor;
            break;

        case EKeyDownArrow:
            ymove = step * crawlFactor;
            break;
            
        case KCodeKeyDown:
        case EKeyPageDown:
            ymove = step * KJumpFactor;
            break;

        case KCodeKeyZoomIn:
        case KCodeKeyZoomIn2:
            Zoom( KZoomInRate );
            break;

        case KCodeKeyZoomOut:
        case KCodeKeyZoomOut2:
            Zoom( KZoomOutRate );
            break;

        case KCodeKeyCenter:
            iModel->GoCenter();
            iCursor = iModel->AbsoluteToScreen( TCoordinate( 0, 0 ) );
            break;

        case KCodeKeySelect:
        case KCodeKeySelect2:
            if ( iSelectionMode )
                {
                iView.HandleUserSelectionL( KErrNone );
                redraw = EFalse;
                }
            break;

        default:
            response = EKeyWasNotConsumed;
            redraw = EFalse;
            break;
        }

    if ( xmove || ymove )
        {
        if ( iSelectionMode )
            {
            MoveCursor( xmove, ymove );
            }
        else
            {
            TCoordinate center = iModel->Center();
            TCoordinate moveTo( 
                center.Latitude() - iModel->ScreenToAbsolute( ymove ),
                center.Longitude() + iModel->ScreenToAbsolute( xmove ) );
            iModel->MoveTo( moveTo );
            }
        }

    if ( redraw )
        {
        RenderL();
        DrawDeferred();
        }

    return response;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::HandleModelUpdateL()
    {
    RenderL();
    DrawDeferred();
    
    TInt ignored = iModel->NumIgnoredLandmarks();
    if ( ignored )
    	{
        CAknInformationNote* note = new (ELeave) CAknInformationNote( ETrue );
        _LIT( KMessageIgnoredLm, "One landmark\nhas no coordinates\nand can't be shown." );
        _LIT( KMessageIgnoredLms, "%d landmarks\nhave no coordinates\nand can't be shown." );
        if ( ignored == 1 )
        	{
        	note->ExecuteLD( KMessageIgnoredLm() );
        	}
        else
        	{
            TBuf<64> message;
        	message.Format( KMessageIgnoredLms, ignored );
        	note->ExecuteLD( message );
        	}
    	}
    }
    
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::CreateScreenBufferL( const TSize& aSize )
	{
	CGraphicsDevice* screenDevice = iEikonEnv->ScreenDevice();

	// create a bitmap to be used off-screen
	CFbsBitmap* offScreenBitmap = new (ELeave) CFbsBitmap();
	User::LeaveIfError( offScreenBitmap->Create( aSize, screenDevice->DisplayMode() ) );
	CleanupStack::PushL( offScreenBitmap );

	if ( iOffScreenBitmap )
		{
		delete iOffScreenBitmap;
		}
	iOffScreenBitmap = offScreenBitmap;

	CleanupStack::Pop( offScreenBitmap );
	}


// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::CreateFonts()
	{
    CGraphicsDevice* screenDevice = iEikonEnv->ScreenDevice();

    const CFont* denseFont = iEikonEnv->DenseFont();
    TFontSpec fs = denseFont->FontSpecInTwips();

    fs.iHeight = KTextFontHeightInTwips;
    screenDevice->GetNearestFontInTwips( iTextFont, fs );
    
    fs.iHeight = KItemFontHeightInTwips;
    screenDevice->GetNearestFontInTwips( iItemFont, fs );
	}

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::DestroyFonts()
	{
	CGraphicsDevice* screenDevice = iEikonEnv->ScreenDevice();
	
    screenDevice->ReleaseFont( iItemFont );
    iItemFont = NULL;
    screenDevice->ReleaseFont( iTextFont );
    iTextFont = NULL;
	}

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::Draw( const TRect& /*aRect*/ ) const
    {
    // Get the standard graphics context
    CWindowGc& gc = SystemGc();

    TRect rect = Rect();
    TRect border( rect );
    border.Shrink( BorderSize() );
	
    gc.Clear( TRect( rect.iTl.iX, rect.iTl.iY, rect.iBr.iX, border.iBr.iY ) );
    gc.Clear( TRect( rect.iTl.iX, border.iBr.iY, rect.iBr.iX, rect.iBr.iY ) );
    gc.Clear( TRect( rect.iTl.iX, border.iTl.iY, border.iTl.iX, border.iBr.iY ) );
    gc.Clear( TRect( border.iBr.iX, border.iTl.iY, rect.iBr.iX, border.iBr.iY ) );

    CMnrpMapModel::TGrid grid;
    iModel->GetGrid( grid );
    DrawGridText( gc, border, rect, iTextFont, grid );

	if ( iOffScreenBitmap )
		{
		gc.BitBlt( border.iTl, iOffScreenBitmap );
		}
	else
		{
		gc.Clear();	
		}
			
    if ( iSelectionMode )
        {
        gc.SetOrigin( border.iTl );
        DrawCursor( gc );
        }

    // draw border
    gc.SetPenColor( KRgbGray );
    gc.SetPenSize( TSize( 1, 1 ) );
    gc.SetOrigin( rect.iTl );
    gc.DrawRect( border );
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::DrawGridText( 
    CWindowGc& aGc, 
    const TRect& aInnerBox,
    const TRect& aOuterBox,
    const CFont* aFont,
    CMnrpMapModel::TGrid& aGrid ) const
    {
    aGc.UseFont( aFont );
    
    TBuf<KMaxCoordStrSize> latTopStr, latBottomStr, lonLeftStr, lonRightStr;
    TBuf<KMaxCoordStrSize> gridMajorStr, latStr, lonStr;
    
    MnrpUtils::CoordinateToString( iModel->Left(), lonLeftStr, ETrue );
    MnrpUtils::CoordinateToString( iModel->Top(), latTopStr, ETrue );
    MnrpUtils::CoordinateToString( iModel->Right(), lonRightStr, ETrue );
    MnrpUtils::CoordinateToString( iModel->Bottom(), latBottomStr, ETrue );

    if ( !iSelectionMode )
        {
        MnrpUtils::CoordinateToString( ( iModel->Right() + iModel->Left() ) / 2, lonStr, ETrue );
        MnrpUtils::CoordinateToString( ( iModel->Top() + iModel->Bottom() ) / 2, latStr, ETrue );
        }
    else
        {
        MnrpUtils::CoordinateToString( iAbsoluteCursor.Longitude(), lonStr, ETrue );
        MnrpUtils::CoordinateToString( iAbsoluteCursor.Latitude(), latStr, ETrue );
        }

    MnrpUtils::CoordinateToString( aGrid.iAbsoluteGridStep, gridMajorStr );

    TRect lonBox( aInnerBox.iTl.iX, 0, aInnerBox.iBr.iX, aInnerBox.iBr.iY );
    TRect latBox( 0, aInnerBox.iTl.iY, aInnerBox.iTl.iX, aInnerBox.iBr.iY );
    TRect centerBox( aInnerBox.iTl.iX, aInnerBox.iBr.iY, aInnerBox.iBr.iX, aOuterBox.iBr.iY );

    TInt textBaseLine = aFont->AscentInPixels() + KBorderSizeFactor / 2;
    TInt vertTextBaseLine = aFont->AscentInPixels() + KBorderSizeFactor / 2;

    aGc.SetPenColor( KGridTextColor );

    aGc.DrawText( lonLeftStr, lonBox, textBaseLine, CGraphicsContext::ELeft );
    aGc.DrawText( lonRightStr, lonBox, textBaseLine, CGraphicsContext::ERight );
    aGc.DrawTextVertical( latTopStr, latBox, vertTextBaseLine, EFalse, CGraphicsContext::ELeft );
    aGc.DrawTextVertical( latBottomStr, latBox, vertTextBaseLine, EFalse, CGraphicsContext::ERight );

    aGc.DrawText( gridMajorStr, lonBox, textBaseLine, CGraphicsContext::ECenter );

    aGc.SetPenColor( KOriginMarkColor );
    aGc.DrawText( latStr, centerBox, textBaseLine, CGraphicsContext::ELeft );
    aGc.DrawText( lonStr, centerBox, textBaseLine, CGraphicsContext::ERight );
    
    aGc.DiscardFont();
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::DrawCursor( CWindowGc& aGc ) const
    {
    aGc.SetPenColor( KCursorColor );
    aGc.SetPenSize( TSize( 1, 1 ) );
    aGc.SetDrawMode( CGraphicsContext::EDrawModeNOTSCREEN );
    
    TRect cursorCircleRect( iCursor, TSize( 0, 0 ) );
    cursorCircleRect.Grow( KCursorCircleRadius, KCursorCircleRadius );
    aGc.DrawEllipse( cursorCircleRect );
    
    // upper vertical line
    aGc.DrawLine( TPoint( iCursor.iX, cursorCircleRect.iTl.iY ), 
                  TPoint( iCursor.iX, cursorCircleRect.iTl.iY - KCursorArrowSize ) );
    // lower vertical line
    aGc.DrawLine( TPoint( iCursor.iX, cursorCircleRect.iBr.iY ), 
                  TPoint( iCursor.iX, cursorCircleRect.iBr.iY + KCursorArrowSize ) );

    // left horiz line
    aGc.DrawLine( TPoint( cursorCircleRect.iTl.iX, iCursor.iY ), 
                  TPoint( cursorCircleRect.iTl.iX - KCursorArrowSize, iCursor.iY ) );
    // right horiz line
    aGc.DrawLine( TPoint( cursorCircleRect.iBr.iX, iCursor.iY ), 
                  TPoint( cursorCircleRect.iBr.iX + KCursorArrowSize, iCursor.iY ) );

    aGc.SetDrawMode( CGraphicsContext::EDrawModePEN );
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::SizeChanged()
    {
    TRect rect( Rect() );
    
    DestroyFonts();
    CreateFonts();
    
    rect.Shrink( BorderSize() );
    iViewSize = rect.Size();
    iModel->SetScreenSize( iViewSize );
    TRAP_IGNORE( CreateScreenBufferL( rect.Size() ) );
    TRAP_IGNORE( RenderL() );
    DrawDeferred();
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::HandleResourceChange( TInt aType )
    {
    CCoeControl::HandleResourceChange( aType );
    if ( aType == KEikDynamicLayoutVariantSwitch )
        {
        SetFullScreen( iIsFullScreen );
        }
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::ToggleFullScreen()
    {
    SetFullScreen( !iIsFullScreen );
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::SetFullScreen( TBool aFullScreen )
    {
    iIsFullScreen = aFullScreen;
    if ( iIsFullScreen)
        {
        SetExtentToWholeScreen();
        }
    else
        {
        SetRect( iView.ClientRect() );
        }
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::MoveCursor( TInt aXmove, TInt aYmove )
    {
    iCursor += TPoint( aXmove, aYmove );

    iCursor.iX = Max( 0, iCursor.iX );
    iCursor.iX = Min( iViewSize.iWidth, iCursor.iX );

    iCursor.iY = Max( 0, iCursor.iY );
    iCursor.iY = Min( iViewSize.iHeight, iCursor.iY );

    // verify cursor margin
    TRect cursorMargin = CursorMargin();
    
    iAbsoluteCursor = iModel->ScreenToAbsolute( iCursor );
    
    TReal xcorrection = 0;
    TReal ycorrection = 0;

    if ( aXmove > 0 ) // moving right
        {
        TInt toMargin = iCursor.iX - cursorMargin.iBr.iX;
        if ( toMargin > 0 ) // cursor went beyond cursor margin, move view
            {
            xcorrection = iModel->ScreenToAbsolute( toMargin );
            }
        }
    else if ( aXmove < 0 ) // moving left
        {
        TInt toMargin = iCursor.iX - cursorMargin.iTl.iX;
        if ( toMargin < 0 )
            {
            xcorrection = iModel->ScreenToAbsolute( toMargin );
            }
        }

    if ( aYmove > 0 ) // moving down
        {
        TInt toMargin = iCursor.iY - cursorMargin.iBr.iY;
        if ( toMargin > 0 )
            {
            ycorrection = -iModel->ScreenToAbsolute( toMargin );
            }
        }
    else if ( aYmove < 0 ) // moving up
        {
        TInt toMargin = iCursor.iY - cursorMargin.iTl.iY;
        if ( toMargin < 0 )
            {
            ycorrection = -iModel->ScreenToAbsolute( toMargin );
            }
        }
    
    TCoordinate center = iModel->Center();
    TCoordinate moveTo( 
        center.Latitude() + ycorrection,
        center.Longitude() + xcorrection );
    iModel->MoveTo( moveTo );

    iCursor = iModel->AbsoluteToScreen( iAbsoluteCursor );
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
TRect CMnrpMapControl::CursorMargin()
    {
    TRect rect( iViewSize );
    rect.Shrink( KCursorMarginSize, KCursorMarginSize );
    return rect;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::Zoom( TReal aRate )
    {
    if ( iSelectionMode )
        {
        iModel->MoveTo( iAbsoluteCursor );
        iModel->Zoom( aRate );
        iCursor = iModel->AbsoluteToScreen( iAbsoluteCursor );
        }
    else
        {
        iModel->Zoom( aRate );
        }
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
TSize CMnrpMapControl::BorderSize() const 
    {
	TSize size( 0, 0 );
	if ( iTextFont )
		{
	    TInt fontHeight = iTextFont->HeightInPixels();
	    
	    size.iWidth = size.iHeight = TInt( fontHeight + KBorderSizeFactor );
		}
    return size;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
void CMnrpMapControl::RenderL()
    {
    TRect rect = Rect();
    TRect border( rect );
    border.Shrink( BorderSize() );

    if ( iOffScreenBitmap && iTextFont && iItemFont )
        {
        iModel->RenderL( *iOffScreenBitmap, TRect( border.Size() ), iTextFont, iItemFont );
        }
    }