pictographs/AknPictograph/src/AknPictographDrawer.cpp
changeset 0 05e9090e2422
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pictographs/AknPictograph/src/AknPictographDrawer.cpp	Thu Dec 17 09:14:12 2009 +0200
@@ -0,0 +1,595 @@
+/*
+* Copyright (c) 2002 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:  Pictograph drawer
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "AknPictographDrawer.h"
+#include "AknPictographConstants.h"
+#include "AknPictographRange.h"
+#include "AknPictographFactory.h"
+#include "AknPictographAnimator.h"
+#include "AknPictographPanic.h"
+#include "AknPictographDrawerFlags.h"
+
+#include <gdi.h>
+#include <fbs.h>
+#include <eikenv.h>
+#include <coecntrl.h>
+
+// CONSTANTS
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::CAknPictographDrawer
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CAknPictographDrawer::CAknPictographDrawer( 
+    MAknPictographAnimatorCallBack& aCallBack ) :
+        iCallBack( aCallBack ), iDrawingMode(EDrawingModeNormal)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::ConstructL()
+    {
+    iAnimator = static_cast<CAknPictographAnimator*>(
+        CCoeEnv::Static( KUidAknPictographAnimator ) );
+
+    if ( !iAnimator )
+        {
+        // adds CCoeStatic in CoeEnv
+        iAnimator = CAknPictographAnimator::CreateSingletonL();
+        }
+
+    iAnimator->AddClientL( *this );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CAknPictographDrawer* CAknPictographDrawer::NewL(
+    MAknPictographAnimatorCallBack& aCallBack )
+    {
+    CAknPictographDrawer* self = 
+        new( ELeave ) CAknPictographDrawer( aCallBack );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// Destructor
+CAknPictographDrawer::~CAknPictographDrawer()
+    {
+    // CCoeStatic list is destroyed in Cone before AppUi, so have to check if
+    // it still exist here.
+    if ( CCoeEnv::Static( KUidAknPictographAnimator ) )
+        {
+        StopAnimator();
+        if ( iAnimator->RemoveClient( *this ) == 0 )
+            {
+            // Removes CCoeStatic
+            delete iAnimator;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::SupportedPictographCodesL
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+HBufC* CAknPictographDrawer::SupportedPictographCodesL() const
+    {
+    return AknPictographFactory::SupportedPictographCodesL();
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::IsPictograph
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+TBool CAknPictographDrawer::IsPictograph( TText aCode ) const
+    {
+    return ( aCode >= KPictographRangeStart &&
+             aCode <= KPictographRangeEnd );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::ContainsPictographs
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+TBool CAknPictographDrawer::ContainsPictographs( const TDesC& aText ) const
+    {
+    const TText* text = aText.Ptr();
+    TInt length( aText.Length() );
+
+    TBool ret( EFalse );
+
+    for ( TInt i = 0 ; i < length ; i++ )
+        {
+        if ( IsPictograph( text[i] ) )
+            {
+            ret = ETrue;
+            break;
+            }
+        }
+
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawPictograph
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawPictograph(
+    CBitmapContext& aGc,
+    const TPoint& aTopLeft,
+    TText aCode,
+    TAknPictographHeight aHeight ) const
+    {
+    iFlags &= ~KFlagNullBrushSet;
+
+    iCurrentHeight = aHeight;
+    TAknPictographData data;
+
+    TInt ret = FetchPictographData( aCode, data );
+
+    if ( ret == KErrNone )
+        {
+        DoDrawPictograph( aGc, aTopLeft, data, NULL );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawPictograph
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawPictograph(
+    CBitmapContext& aGc,
+    const TRect& aRect,
+    TText aCode,
+    TAknPictographHeight aHeight ) const
+    {
+    DrawPictograph(
+        aGc,
+        aRect,
+        aRect,
+        aCode,
+        aHeight );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawPictograph
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawPictograph(
+    CBitmapContext& aGc,
+    const TRect& aRect,
+    const TRect& aClipRect,
+    TText aCode,
+    TAknPictographHeight aHeight ) const
+    {
+    iFlags &= ~KFlagNullBrushSet;
+
+    iCurrentHeight = aHeight;
+    TAknPictographData data;
+
+    TInt ret = FetchPictographData( aCode, data );
+
+    if ( ret == KErrNone )
+        {
+        // Center the pictograph bitmap in the given rect.
+        // Round to the left and down if required.
+
+        TRect pictoRect( aRect );
+
+        TInt rectWidth = aRect.Width();
+        TInt rectHeight = aRect.Height();
+
+        if ( data.iSize.iWidth < rectWidth )
+            {
+            pictoRect.iTl.iX += ( rectWidth - data.iSize.iWidth ) / 2;
+            }
+        if ( data.iSize.iHeight < rectHeight )
+            {
+            // +1 makes rounding down instead of up.
+            pictoRect.iTl.iY += ( rectHeight - data.iSize.iHeight + 1 ) / 2;
+            }
+
+        pictoRect.iBr.iX = pictoRect.iTl.iX + data.iSize.iWidth;
+        pictoRect.iBr.iY = pictoRect.iTl.iY + data.iSize.iHeight;
+
+        // Calculate rect that is drawn in the pictograph bitmap,
+        // based on cliprect.
+
+        TRect intersection = pictoRect;
+        intersection.Intersection( aClipRect );
+
+        TPoint topLeft = intersection.iTl;
+
+        // change rect coordinates relative to bitmap's top left
+        intersection.Move( -pictoRect.iTl.iX, -pictoRect.iTl.iY );
+
+        DoDrawPictograph( aGc, topLeft, data, &intersection );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawText
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawText(
+    CBitmapContext& aGc,
+    const CFont& aFont,
+    const TDesC& aText,
+    const TPoint& aPosition ) const
+    {
+    aGc.DrawText( aText, aPosition );
+    DrawPictographsInText( aGc, aFont, aText, aPosition );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawText
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawText(
+    CBitmapContext& aGc,
+    const CFont& aFont,
+    const TDesC& aText,
+    const TRect& aBox,
+    TInt aBaselineOffset,
+    CGraphicsContext::TTextAlign aAlignment,
+    TInt aLeftMargin ) const
+    {
+    aGc.DrawText( aText, aBox, aBaselineOffset, aAlignment, aLeftMargin );
+
+    DrawPictographsInText( 
+        aGc, aFont, aText, aBox, aBaselineOffset, aAlignment, aLeftMargin );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawPictographsInText
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawPictographsInText(
+    CBitmapContext& aGc,
+    const CFont& aFont,
+    const TDesC& aText,
+    const TPoint& aPosition ) const
+    {
+    if ( !ContainsPictographs( aText ) )
+        {
+        return;
+        }
+
+    DrawPictographs( aGc, aFont, aText, aPosition, NULL );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawPictographsInText
+// -- API method --
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawPictographsInText(
+    CBitmapContext& aGc,
+    const CFont& aFont,
+    const TDesC& aText,
+    const TRect& aBox,
+    TInt aBaselineOffset,
+    CGraphicsContext::TTextAlign aAlignment,
+    TInt aMargin ) const
+    {
+    if ( !ContainsPictographs( aText ) )
+        {
+        return;
+        }
+
+    // Work out the text layout.
+    TPoint p( aBox.iTl );
+    p.iY += aBaselineOffset;
+
+    if ( aAlignment == CGraphicsContext::ELeft )
+        {
+        p.iX += aMargin;
+        }
+    else
+        {
+        // measure the text
+	    CFont::TMeasureTextInput input;
+	    input.iFlags |= CFont::TMeasureTextInput::EFVisualOrder;
+	    TInt textWidth = aFont.MeasureText( aText, &input );
+
+        if ( aAlignment == CGraphicsContext::ERight )
+            {
+            p.iX = aBox.iBr.iX - aMargin - textWidth;
+            }
+        else if ( aAlignment == CGraphicsContext::ECenter )
+            {
+            p.iX += aBox.Width() / 2 + aMargin - textWidth / 2;
+            }
+        }
+
+    DrawPictographs( aGc, aFont, aText, p, &aBox );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::IsAnimated
+// -----------------------------------------------------------------------------
+//
+TBool CAknPictographDrawer::IsAnimated(
+    TText aCode, TAknPictographHeight aHeight ) const
+    {
+    TAknPictographData data;
+
+    return AknPictographFactory::AnimatedPictographData(
+        aCode, aHeight, 0, data ) == KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::SelectPictographHeightForFont
+// -----------------------------------------------------------------------------
+//
+TInt CAknPictographDrawer::SelectPictographHeightForFont(
+            const CFont& aFont,
+            TAknPictographHeight& aHeight ) const
+    {
+    return AknPictographFactory::SelectPictographHeightForFont(aFont,aHeight);
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::SetPictographDrawingMode
+// -----------------------------------------------------------------------------
+//
+TAknPictographDrawingMode CAknPictographDrawer::SetPictographDrawingMode(
+            TAknPictographDrawingMode aDrawingMode)
+    {
+    TAknPictographDrawingMode currentDrawingMode = iDrawingMode;
+    iDrawingMode = aDrawingMode;
+    return currentDrawingMode;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DrawPictographs
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DrawPictographs(
+    CBitmapContext& aGc,
+    const CFont& aFont,
+    const TDesC& aText,
+    const TPoint& aPosition,
+    const TRect* aClipRect ) const
+    {
+
+    // Choose pictograph height based on font.
+    if( AknPictographFactory::SelectPictographHeightForFont(
+            aFont,
+            iCurrentHeight
+            ) != KErrNone)
+
+        {
+        return;
+        }
+
+    TInt topY = aPosition.iY - aFont.AscentInPixels();
+    TInt bottomY = aPosition.iY + aFont.DescentInPixels();
+
+    const TText* text = aText.Ptr();
+    TInt length( aText.Length() );
+
+    iFlags &= ~KFlagNullBrushSet;
+    iFlags |= KFlagDrawingMultiplePictographs;
+   
+
+    // Draw the pictographs in loop.
+    for ( TInt i = 0 ; i < length ; i++ )
+        {
+        if ( IsPictograph( text[i] ) )
+            {
+            TInt x = aPosition.iX;
+            x += aFont.TextWidthInPixels( aText.Left( i ) );
+
+            TRect rect( x, topY, x + aFont.CharWidthInPixels( text[i] ), bottomY );
+            TRect clipRect = aClipRect ? *aClipRect : rect;
+
+            DrawPictograph(
+                aGc, 
+                rect,
+                clipRect,
+                text[i],
+                iCurrentHeight );
+            }
+        }
+    iFlags &= ~KFlagDrawingMultiplePictographs;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::HandleGainingForeground
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::HandleGainingForeground()
+    {
+    StartAnimatorIfRequired();
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::HandleLosingForeground
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::HandleLosingForeground()
+    {
+    StopAnimator();
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::DoDrawPictograph
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::DoDrawPictograph( 
+    CBitmapContext& aGc,
+    const TPoint& aTopLeft,
+    const TAknPictographData& aData,
+    TRect* aRect ) const
+    {
+    // First get the index for accessing the correct bitmap
+    // This also validates iCurrentHeight 
+    TUint bitmapIndex;
+    if( AknPictographFactory::GetArrayIndexForHeight(iCurrentHeight,bitmapIndex) != KErrNone )
+        {
+        return;
+        }
+
+    if ( aData.iAnimated )
+        {
+        // Animated pictographs used
+        iFlags |= KFlagAnimatedPictographs;
+        StartAnimatorIfRequired();
+        }
+
+    TRect rect = aRect ? *aRect : TRect( aData.iSize );
+
+    // Move to the correct x-offset in the pictograph collection bitmap
+    rect.Move( aData.iOffset, 0 );
+
+    RPointerArray<CFbsBitmap>* bitmaps = iAnimator->Bitmaps();
+    RPointerArray<CFbsBitmap>* masks = iAnimator->Masks();
+
+    CFbsBitmap* bitmap = (*bitmaps)[bitmapIndex];
+    CFbsBitmap* mask = (*masks)[bitmapIndex];
+
+
+    if ( EDrawingModeWhite==iDrawingMode && 
+         !(iFlags & KFlagDrawingMultiplePictographs) )
+        {
+        // Note: EDrawingModeWhite is supported only if 
+        // a single pictograph is drawn only per component->Draw() call.
+        // This restriction is needed because aGc.BitBltMasked calls are cached
+        // in client side as a result only the last pictograph will be drawn
+        // in place all other aGc.BitBltMasked calls.
+        bitmap = iAnimator->WhiteBitmap();
+        CFbsBitGc* maskGc = iAnimator->WhiteBitmapMaskGc();
+        maskGc->Clear();
+        maskGc->BitBlt(TPoint(0,0), mask, rect);
+        mask = iAnimator->WhiteBitmapMask();
+        rect.Move( -rect.iTl );
+        }
+    
+    if ( !( iFlags & KFlagNullBrushSet ) )
+        {
+        // To minimize WS buffer consumption, we set null brush
+        // only once per API call.
+        aGc.SetBrushStyle( CGraphicsContext::ENullBrush );
+        iFlags |= KFlagNullBrushSet;
+        }
+
+    aGc.BitBltMasked(
+        aTopLeft,
+        bitmap,
+        rect,
+        mask,
+        ETrue );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::AnimationTick
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::AnimationTick()
+    {
+    // Clear animated pictographs flag before callback to see whether they are
+    // needed any more or not (the flag will be updated during the callback).
+    iFlags &= ~KFlagAnimatedPictographs;
+
+    iCallBack.DrawPictographArea();
+
+    // If no animation was required during the redraw callback,
+    // stop the animator.
+    // It will be started again when a request to draw an animated pictograph
+    // is detected.
+    if ( !( iFlags & KFlagAnimatedPictographs ) )
+        {
+        StopAnimator();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::StartAnimatorIfRequired
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::StartAnimatorIfRequired() const
+    {
+    TInt bits = iFlags & ( KFlagAnimatedPictographs | KFlagTimerStarted );
+
+    // Animated pictographs but timer not started?
+    if ( bits == KFlagAnimatedPictographs )
+        {
+        iAnimator->Start();
+        iFlags |= KFlagTimerStarted;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::StopAnimator
+// -----------------------------------------------------------------------------
+//
+void CAknPictographDrawer::StopAnimator() const
+    {
+    if ( iFlags & KFlagTimerStarted )
+        {
+        iAnimator->Stop();
+        iFlags &= ~KFlagTimerStarted;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknPictographDrawer::FetchPictographData
+// -----------------------------------------------------------------------------
+//
+TInt CAknPictographDrawer::FetchPictographData(
+    TText aCode,
+    TAknPictographData& aData ) const
+    {
+    TInt ret = AknPictographFactory::StaticPictographData(
+        aCode, iCurrentHeight, aData );
+
+    if ( ret != KErrNone )
+        {
+        ret = AknPictographFactory::AnimatedPictographData(
+            aCode, iCurrentHeight, iAnimator->Counter(), aData );
+        }
+
+    return ret;
+    }
+
+//  End of File