--- /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