diff -r 000000000000 -r 05e9090e2422 pictographs/AknPictograph/src/AknPictographDrawer.cpp --- /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 +#include +#include +#include + +// 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( + 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* bitmaps = iAnimator->Bitmaps(); + RPointerArray* 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