--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/src/AknTitlePaneLabel.cpp Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,1467 @@
+/*
+* Copyright (c) 2005-2007 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: Implementation of title pane's label.
+*
+*/
+
+
+// SYSTEM INCLUDES
+#include <e32def.h>
+#include <AknPictographInterface.h>
+#include <AknPictographDrawerInterface.h>
+#include <bidivisual.h>
+#include <biditext.h>
+#include <akniconconfig.h>
+#include <layoutmetadata.cdl.h>
+
+#include <AknTasHook.h> // for testability hooks
+// USER INCLUDES
+#include "AknTitlePaneLabel.h"
+#include "AknUtils.h"
+#include "AknLayoutFont.h"
+#include "aknappui.h"
+#include "AknBidiTextUtils.h"
+#include "AknStatuspaneUtils.h"
+
+// General effects-related constants
+const TInt KScrollTimerInterval = 50000; // 20 events/s
+const TInt KScrollTimerDelay = KScrollTimerInterval;
+const TInt KScrollTimerDelayBeforeDirectionReversal = 3000000; // 3s
+const TInt KStartValue = 0;
+const TInt KEndValue = 255;
+const TInt KMinInterval = 50000;
+const TInt KScaleMagicNumber = 208;
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+CAknTitlePaneLabel::CAknTitlePaneLabel()
+ {
+ AKNTASHOOK_ADD( this, "CAknTitlePaneLabel" );
+ }
+
+
+CAknTitlePaneLabel::~CAknTitlePaneLabel()
+ {
+ AKNTASHOOK_REMOVE();
+ delete iMask;
+ delete iMaskDevice;
+ delete iMaskGc;
+
+ delete iBitmap;
+ delete iBitmapDevice;
+ delete iBitmapGc;
+
+ if ( iEffectTimer )
+ {
+ iEffectTimer->Cancel();
+ delete iEffectTimer;
+ ControlEnv()->RemoveForegroundObserver( *this );
+ }
+ delete iEffectQueue;
+ delete iScrollingText;
+ }
+
+
+void CAknTitlePaneLabel::Draw( const TRect& aRect ) const
+ {
+ if ( iEffect == EEffectNone )
+ {
+ CEikLabel::Draw( aRect );
+ }
+
+ // Text is paused before starting to scroll,
+ // drawn without truncation character.
+ else if ( iEffect == EEffectPause && iPreviousEffect == EEffectNone )
+ {
+ // const_cast is required to call the DrawWithoutTruncation() function.
+ TRAPD( err,
+ const_cast<CAknTitlePaneLabel*>( this )->DrawWithoutTruncationL( aRect ) );
+
+ if ( err != KErrNone )
+ {
+ CEikLabel::Draw( aRect );
+ }
+ }
+ else
+ {
+ DrawWithEffect( aRect );
+ }
+ }
+
+
+void CAknTitlePaneLabel::DrawWithoutTruncationL( const TRect& aRect )
+ {
+ // Copy of the truncated text in CEikLabel is made first.
+ HBufC* truncatedText = HBufC::NewL( Text()->Length() );
+ CleanupStack::PushL( truncatedText );
+
+ TPtr ptr( truncatedText->Des() );
+ ptr.Copy( *Text() );
+
+ // CEikLabel's text is set to the full text and is drawn.
+ SetTextL( *iScrollingText );
+ CEikLabel::Draw( aRect );
+
+ // CEikLabel's text is set back to the truncated form.
+ SetTextL( ptr );
+
+ CleanupStack::PopAndDestroy( truncatedText );
+ }
+
+
+void CAknTitlePaneLabel::DrawWithEffect( const TRect& aRect ) const
+ {
+ if ( iEffect && iBitmap && iMask && iBitmapGc && iMaskGc )
+ {
+ // Bitblit using mask, this creates the fade effect
+ CWindowGc& gc = SystemGc();
+ gc.BitBltMasked(
+ iTextLayout.TextRect().iTl,
+ iBitmap,
+ iTextLayout.TextRect(),
+ iMask,
+ ETrue );
+ }
+ else
+ {
+ CEikLabel::Draw( aRect );
+ }
+ }
+
+
+void CAknTitlePaneLabel::DrawTextWithEffect() const
+ {
+ switch ( iEffect )
+ {
+ case EEffectFadeToLeft:
+ case EEffectFadeToRight:
+ {
+ DrawTextWithFadeEffect();
+ break;
+ }
+ case EEffectDefaultScroll:
+ {
+ DrawTextWithScrollEffect();
+ break;
+ }
+ case EEffectDefaultScrollWithFade:
+ case EEffectLoopScrollWithFade:
+ case EEffectScrollOnceWithFade:
+ case EEffectFadeOut:
+ case EEffectFadeIn:
+ case EEffectToggleScrolledTextTruncation:
+ {
+ DrawTextWithScrollAndFadeEffect();
+ break;
+ }
+ case EEffectPause:
+ case EEffectNone:
+ default:
+ {
+ break;
+ }
+ }
+
+ if ( DrawableWindow() )
+ {
+ DrawDeferred();
+ }
+
+ if ( iObserver && iObserver->DrawableWindow() )
+ {
+ iObserver->DrawDeferred();
+ }
+ }
+
+
+void CAknTitlePaneLabel::DrawTextWithFadeEffect() const
+ {
+ if ( iEffect &&
+ iBitmap &&
+ iMask &&
+ iBitmapGc &&
+ iMaskGc &&
+ iTitleText &&
+ iScrollingText )
+ {
+ InitBitmaps();
+ iMaskGc->SetPenStyle( CGraphicsContext::ESolidPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+ iBitmapGc->SetPenStyle( CGraphicsContext::ESolidPen );
+ iBitmapGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+
+ if ( IsStrikethrough() )
+ {
+ iMaskGc->SetStrikethroughStyle( EStrikethroughOn );
+ iBitmapGc->SetStrikethroughStyle( EStrikethroughOn );
+ }
+ else
+ {
+ iMaskGc->SetStrikethroughStyle( EStrikethroughOff );
+ iBitmapGc->SetStrikethroughStyle( EStrikethroughOff );
+ }
+
+ if ( IsUnderlined() )
+ {
+ iMaskGc->SetUnderlineStyle( EUnderlineOn );
+ iBitmapGc->SetUnderlineStyle( EUnderlineOn );
+ }
+ else
+ {
+ iMaskGc->SetUnderlineStyle( EUnderlineOff );
+ iBitmapGc->SetUnderlineStyle( EUnderlineOff );
+ }
+
+ const CFont* fontUsed =
+ AknLayoutUtils::FontFromId( iTextLayoutLine.FontId() );
+ iBitmapGc->UseFont( fontUsed );
+
+ // First draw with white color for masking purpose
+ const CAknLayoutFont* layoutFont =
+ CAknLayoutFont::AsCAknLayoutFontOrNull( fontUsed );
+ TInt textPaneAscent( 0 );
+ if ( layoutFont )
+ {
+ textPaneAscent = layoutFont->TextPaneTopToBaseline();
+ }
+ else
+ {
+ textPaneAscent = fontUsed->AscentInPixels();
+ }
+
+ CGraphicsContext::TTextAlign textAlign( CGraphicsContext::ELeft );
+ if( AknLayoutUtils::LayoutMirrored() )
+ {
+ textAlign = CGraphicsContext::ERight;
+ }
+
+ iBitmapGc->SetPenColor( KRgbWhite );
+ iBitmapGc->DrawText( *iScrollingText,
+ iTextLayout.TextRect(),
+ textPaneAscent,
+ textAlign,
+ 0 );
+
+ // Draw pictographs
+ if ( iPictographInterface )
+ {
+ iPictographInterface->Interface()->DrawPictographsInText(
+ *iBitmapGc,
+ *fontUsed,
+ *iScrollingText,
+ iTextLayout.TextRect(),
+ textPaneAscent,
+ textAlign,
+ 0 );
+ }
+
+ // Draw text to mask
+ iMaskGc->BitBltMasked(
+ Rect().iTl,
+ iBitmap,
+ TRect( iBitmap->SizeInPixels() ),
+ iBitmap,
+ ETrue );
+
+ TRgb color( KRgbBlack );
+ if ( IsDimmed() )
+ {
+ color = iEikonEnv->ControlColor( EColorLabelDimmedText, *this );
+ }
+ else
+ {
+ color = iEikonEnv->ControlColor( EColorLabelText, *this );
+ }
+
+ iBitmapGc->SetPenColor( color );
+ iBitmapGc->DrawText( *iScrollingText,
+ iTextLayout.TextRect(),
+ textPaneAscent,
+ textAlign,
+ 0 );
+
+ // Draw pictographs
+ if ( iPictographInterface )
+ {
+ iPictographInterface->Interface()->DrawPictographsInText(
+ *iBitmapGc,
+ *fontUsed,
+ *iScrollingText,
+ iTextLayout.TextRect(),
+ textPaneAscent,
+ textAlign,
+ 0 );
+ }
+
+ iBitmapGc->DiscardFont(); // Release the font cache
+ }
+ }
+
+void CAknTitlePaneLabel::DrawTextWithScrollEffect() const
+ {
+ if ( iEffect &&
+ iBitmap &&
+ iMask &&
+ iBitmapGc &&
+ iMaskGc &&
+ iTitleText &&
+ iScrollingText )
+ {
+ InitBitmaps();
+ iMaskGc->SetPenStyle( CGraphicsContext::ESolidPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+ iBitmapGc->SetPenStyle( CGraphicsContext::ESolidPen );
+ iBitmapGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+
+ TRect rect( iScrollRect );
+
+ TRgb color( KRgbBlack );
+ if ( IsDimmed() )
+ {
+ color = iEikonEnv->ControlColor( EColorLabelDimmedText, *this );
+ }
+ else
+ {
+ color = iEikonEnv->ControlColor( EColorLabelText, *this );
+ }
+
+ const CFont* fontUsed =
+ AknLayoutUtils::FontFromId( iTextLayoutLine.FontId() );
+ const CAknLayoutFont* layoutFont =
+ CAknLayoutFont::AsCAknLayoutFontOrNull( fontUsed );
+ TInt textPaneAscent( 0 );
+ if ( layoutFont )
+ {
+ textPaneAscent = layoutFont->TextPaneTopToBaseline();
+ }
+ else
+ {
+ textPaneAscent = fontUsed->AscentInPixels();
+ }
+
+ CGraphicsContext::TTextAlign textAlign( CGraphicsContext::ELeft );
+
+ if ( iWesternText )
+ {
+ rect.iTl.iX -= iScrollPosition;
+ }
+ else
+ {
+ rect.iBr.iX += iScrollPosition;
+ textAlign = CGraphicsContext::ERight;
+ }
+
+ iBitmapGc->SetPenColor( KRgbWhite );
+ iBitmapGc->UseFont( fontUsed );
+
+ TBool truncated = Text()->Locate( KEllipsis ) != KErrNotFound;
+ if ( !iScrollPosition && truncated )
+ {
+ // Draw truncated text
+ iBitmapGc->DrawText( *Text(), rect, textPaneAscent, textAlign, 0 );
+ // Draw pictographs
+ if ( iPictographInterface )
+ {
+ iPictographInterface->Interface()->DrawPictographsInText(
+ *iBitmapGc,
+ *fontUsed,
+ *Text(),
+ rect,
+ textPaneAscent,
+ textAlign,
+ 0 );
+ }
+ }
+ else if ( iScrollingText )
+ {
+ // Draw non-truncated text
+ iBitmapGc->DrawText( *iScrollingText,
+ rect,
+ textPaneAscent,
+ textAlign,
+ 0 );
+ // Draw pictographs
+ if ( iPictographInterface )
+ {
+ iPictographInterface->Interface()->DrawPictographsInText(
+ *iBitmapGc,
+ *fontUsed,
+ *iScrollingText,
+ rect,
+ textPaneAscent,
+ textAlign,
+ 0 );
+ }
+ }
+
+ // Draw text to mask
+ iMaskGc->BitBltMasked(
+ Rect().iTl,
+ iBitmap,
+ TRect( iBitmap->SizeInPixels() ),
+ iBitmap,
+ ETrue );
+
+ iBitmapGc->SetPenColor( color );
+
+ if ( !iScrollPosition && truncated )
+ {
+ // Draw truncated text
+ iBitmapGc->DrawText( *Text(), rect, textPaneAscent, textAlign, 0 );
+ // Draw pictographs
+ if ( iPictographInterface )
+ {
+ iPictographInterface->Interface()->DrawPictographsInText(
+ *iBitmapGc,
+ *fontUsed,
+ *Text(),
+ rect,
+ textPaneAscent,
+ textAlign,
+ 0 );
+ }
+ }
+ else if ( iScrollingText )
+ {
+ // Draw non-truncated text
+ iBitmapGc->DrawText( *iScrollingText,
+ rect,
+ textPaneAscent,
+ textAlign,
+ 0 );
+ // Draw pictographs
+ if ( iPictographInterface )
+ {
+ iPictographInterface->Interface()->DrawPictographsInText(
+ *iBitmapGc,
+ *fontUsed,
+ *iScrollingText,
+ rect,
+ textPaneAscent,
+ textAlign,
+ 0 );
+ }
+ }
+
+ iBitmapGc->DiscardFont(); // Release the font cache
+ }
+ }
+
+
+void CAknTitlePaneLabel::DrawTextWithScrollAndFadeEffect() const
+ {
+ DrawTextWithScrollEffect();
+ }
+
+
+void CAknTitlePaneLabel::SetTextEffect( TInt aEffect,
+ TRect aEffectRect,
+ TInt aEffectDuration,
+ TRect aLabelRect,
+ TAknLayoutText aTextLayout,
+ TAknTextLineLayout aTextLayoutLine,
+ HBufC* aTitleText,
+ CCoeControl* aObserver)
+ {
+ iPreviousEffect = iEffect;
+
+ iObserver = aObserver;
+ iTextLayout = aTextLayout;
+ iTextLayoutLine = aTextLayoutLine;
+
+ if ( ( iTitleText != aTitleText && iScrollingText ) ||
+ ( !iScrollingText && aEffect ) )
+ {
+ TRAP_IGNORE( CreateScrollingTextL( aTitleText ) );
+ }
+
+ iTitleText = aTitleText;
+ iEffectDuration = aEffectDuration;
+
+ iWesternText =
+ TBidiText::TextDirectionality( *Text() ) == TBidiText::ELeftToRight;
+
+ if ( aEffect == EEffectScrollOnceWithFade ||
+ aEffect == EEffectLoopScrollWithFade ||
+ aEffect == EEffectLoopScroll ||
+ aEffect == EEffectDefaultScrollWithFade ||
+ aEffect == EEffectDefaultScroll )
+ {
+ iScrollPosition = 0;
+ }
+
+ iScrollRect = iTextLayout.TextRect();
+ if ( iScrollRect.iTl.iX < aEffectRect.iTl.iX )
+ {
+ iScrollRect.iTl.iX = aEffectRect.iTl.iX;
+ }
+ if ( iScrollRect.iBr.iX > aEffectRect.iBr.iX )
+ {
+ iScrollRect.iBr.iX = aEffectRect.iBr.iX;
+ }
+
+ const CFont* fontUsed =
+ AknLayoutUtils::FontFromId( aTextLayoutLine.FontId() );
+ CFont::TMeasureTextInput input;
+ input.iFlags = CFont::TMeasureTextInput::EFVisualOrder;
+ iTextLength = fontUsed->MeasureText( *aTitleText, &input );
+
+ iOperatorNamePhase = 0;
+
+ if ( !aEffect ||
+ iEffect != aEffect ||
+ iEffectRect != aEffectRect ||
+ Rect() != aLabelRect )
+ {
+ iEffect = aEffect;
+ iEffectRect = aEffectRect;
+ if ( !iEffect )
+ {
+ TRgb color( iEikonEnv->ControlColor( EColorLabelText, *this ) );
+ // We cast here a bit dangerously, this might be changed someday.
+ TAknMultiLineTextLayout* multilinePtr = NULL;
+ multilinePtr =
+ static_cast<TAknMultiLineTextLayout*> ( &aTextLayoutLine );
+ AknLayoutUtils::LayoutLabel(this, aLabelRect, *multilinePtr);
+ // Layoutlabel loses the color, set it back to right one
+ TRAP_IGNORE(
+ AknLayoutUtils::OverrideControlColorL(
+ *this, EColorLabelText, color ) );
+ }
+ else
+ {
+ if ( aEffect != EEffectPause )
+ {
+ SetRect( aLabelRect );
+ }
+ }
+
+ iEffectLabelSize = Size();
+
+ TInt error = KErrNone;
+ TRAP( error, InitEffectL() );
+ if ( error != KErrNone )
+ {
+ iEffect = EEffectNone;
+ }
+ }
+
+ // Do effect event at least once
+ DoEffectEvent();
+
+ // Setup timer for furter effect events if needed
+ if ( iEffect != EEffectPause )
+ {
+ TRAP_IGNORE( InitTimerL( KScrollTimerDelay, KScrollTimerInterval ) );
+ }
+ }
+
+
+TInt CAknTitlePaneLabel::TextEffect()
+ {
+ return iEffect;
+ }
+
+
+void CAknTitlePaneLabel::InitEffectL()
+ {
+ if ( EffectBitmapsNeeded( iEffect ) )
+ {
+ delete iMask;
+ iMask = NULL;
+ delete iMaskDevice;
+ iMaskDevice = NULL;
+ delete iMaskGc;
+ iMaskGc = NULL;
+
+ delete iBitmap;
+ iBitmap = NULL;
+ delete iBitmapDevice;
+ iBitmapDevice = NULL;
+ delete iBitmapGc;
+ iBitmapGc = NULL;
+
+ iMask = new (ELeave) CFbsBitmap();
+ iMask->Create( Size(), EGray256 );
+ iMaskDevice = CFbsBitmapDevice::NewL( iMask );
+ iMaskDevice->CreateContext( iMaskGc );
+
+ AknIconConfig::TPreferredDisplayMode mode;
+ AknIconConfig::PreferredDisplayMode(
+ mode,
+ AknIconConfig::EImageTypeOffscreen );
+
+ iBitmap = new (ELeave) CFbsBitmap();
+ iBitmap->Create( Size(), mode.iBitmapMode );
+ iBitmapDevice = CFbsBitmapDevice::NewL( iBitmap );
+ iBitmapDevice->CreateContext( iBitmapGc );
+
+ InitBitmaps();
+ }
+ }
+
+
+void CAknTitlePaneLabel::InitTimerL( TInt aDelay, TInt aInterval )
+ {
+ CancelTimer();
+
+ if ( EffectEventsNeeded( iEffect ) )
+ {
+ if ( !iEffectTimer )
+ {
+ iEffectTimer = CPeriodic::NewL( CActive::EPriorityIdle );
+ ControlEnv()->AddForegroundObserverL( *this );
+ }
+
+ if ( !iEffectTimer->IsActive() ) // start timer if not already started
+ {
+ iEffectTimer->Start(
+ TTimeIntervalMicroSeconds32( aDelay ),
+ TTimeIntervalMicroSeconds32( aInterval ),
+ TCallBack( CAknTitlePaneLabel::EffectEvent, this ) );
+ }
+ }
+ else
+ {
+ iScrollPosition = 0;
+ }
+ }
+
+
+void CAknTitlePaneLabel::CancelTimer()
+ {
+ if ( iEffectTimer && iEffectTimer->IsActive() )
+ {
+ iEffectTimer->Cancel();
+ }
+ }
+
+
+void CAknTitlePaneLabel::InitBitmaps() const
+ {
+ iBitmapGc->SetPenColor( KRgbBlack );
+ iBitmapGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iBitmapGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iBitmapGc->SetBrushColor( KRgbBlack );
+ iBitmapGc->DrawRect( TRect( Size() ) );
+
+ iMaskGc->SetPenColor( KRgbBlack );
+ iMaskGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iMaskGc->SetBrushColor( KRgbWhite );
+ iMaskGc->DrawRect( TRect( Size() ) );
+
+ iMaskGc->SetPenStyle( CGraphicsContext::ESolidPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+
+ TInt width = iEffectRect.Width();
+
+ TRect parentRect( Rect() );
+
+ TBool isLandscape( Layout_Meta_Data::IsLandscapeOrientation() );
+ TBool flatSp( AknStatuspaneUtils::FlatLayoutActive() );
+
+ switch ( iEffect )
+ {
+ case EEffectFadeToLeft:
+ {
+ TInt KMaxFadeSteps = KEndValue - KStartValue;
+ TInt usedFadeStep = 0;
+ TInt usedDrawStep = 1;
+
+ if ( width < KMaxFadeSteps &&
+ width != 0)
+ {
+ usedFadeStep = KMaxFadeSteps / width;
+ }
+ else
+ {
+ usedFadeStep = 1;
+ usedDrawStep = width / KMaxFadeSteps;
+ }
+
+ TInt startValue( KStartValue );
+
+ // In portrait mode flat status pane layout
+ // we fade the text fully, because the navi
+ // pane content and title pane can't be displayed
+ // at the same time.
+
+ TRgb rgb;
+ rgb.SetRed( startValue );
+ rgb.SetGreen( startValue );
+ rgb.SetBlue( startValue );
+
+ TRect rect;
+ for ( TInt x = 0; x < width; x += usedDrawStep )
+ {
+ iMaskGc->SetPenColor( rgb );
+ iMaskGc->SetBrushColor( rgb );
+ rect.iTl.iX = iEffectRect.iTl.iX + x;
+ rect.iTl.iY = 0;
+ rect.iBr.iX = rect.iTl.iX + usedDrawStep;
+ rect.iBr.iY = rect.iTl.iY + parentRect.Height();
+
+ iMaskGc->DrawRect( rect );
+ rgb.SetRed( rgb.Red() + usedFadeStep );
+ rgb.SetGreen( rgb.Green() + usedFadeStep );
+ rgb.SetBlue( rgb.Blue() + usedFadeStep );
+ }
+
+ iMaskGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iMaskGc->SetPenColor( KRgbBlack );
+ iMaskGc->SetBrushColor( KRgbBlack );
+ iMaskGc->DrawRect( TRect( parentRect.iTl.iX,
+ parentRect.iTl.iY,
+ iEffectRect.iTl.iX,
+ parentRect.iBr.iY ) );
+ break;
+ }
+ case EEffectFadeToRight:
+ {
+ TInt KMaxFadeSteps = KEndValue - KStartValue;
+ TInt usedFadeStep = 0;
+ TInt usedDrawStep = 1;
+
+
+ if ( width < KMaxFadeSteps &&
+ width != 0 )
+ {
+ usedFadeStep = KMaxFadeSteps / width;
+ }
+ else
+ {
+ usedFadeStep = 1;
+ usedDrawStep = width / KMaxFadeSteps;
+ }
+
+ TInt startValue( KStartValue );
+
+ // In portrait mode flat status pane layout
+ // we fade the text fully, because the navi
+ // pane content and title pane can't be displayed
+ // at the same time.
+
+ TRgb rgb;
+ rgb.SetRed( startValue );
+ rgb.SetGreen( startValue );
+ rgb.SetBlue( startValue );
+
+ TRect rect;
+ for ( TInt x = width - 1; x >= 0; x -= usedDrawStep )
+ {
+ iMaskGc->SetPenColor( rgb );
+ iMaskGc->SetBrushColor( rgb );
+ rect.iTl.iX = iEffectRect.iTl.iX + x;
+ rect.iTl.iY = 0;
+ rect.iBr.iX = rect.iTl.iX + usedDrawStep;
+ rect.iBr.iY = rect.iTl.iY + parentRect.Height();
+ iMaskGc->DrawRect( rect );
+ rgb.SetRed( rgb.Red() + usedFadeStep );
+ rgb.SetGreen( rgb.Green() + usedFadeStep );
+ rgb.SetBlue( rgb.Blue() + usedFadeStep );
+ }
+
+ iMaskGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iMaskGc->SetPenColor( KRgbBlack );
+ iMaskGc->SetBrushColor( KRgbBlack );
+ iMaskGc->DrawRect( TRect( iEffectRect.iBr.iX,
+ parentRect.iTl.iY,
+ parentRect.iBr.iX,
+ parentRect.iBr.iY ) );
+ break;
+ }
+ case EEffectDefaultScrollWithFade:
+ case EEffectLoopScrollWithFade:
+ case EEffectScrollOnceWithFade:
+ {
+ if ( !TextNeedsTruncation() || iScrollPosition == 0 )
+ {
+ return; // No need to fade if not even scrolled.
+ }
+
+ // We fade about 5-10% of the text area end/start to make
+ // scrolling text appear/disappear smoother.
+ width = iEffectRect.Width() / 30;
+ TRect leftFadeEffectRect( iEffectRect );
+ leftFadeEffectRect.iBr.iX = leftFadeEffectRect.iTl.iX + width;
+
+ TRect rightFadeEffectRect = iEffectRect;
+ rightFadeEffectRect.iTl.iX = rightFadeEffectRect.iBr.iX - width;
+
+ TInt KMaxFadeSteps = KEndValue - KStartValue;
+ TInt usedFadeStep = 0;
+ TInt usedDrawStep = 1;
+
+ if ( width < KMaxFadeSteps &&
+ width != 0 )
+ {
+ usedFadeStep = KMaxFadeSteps / width;
+ }
+ else
+ {
+ usedFadeStep = 1;
+ usedDrawStep = width / KMaxFadeSteps;
+ }
+
+ TRgb rgb;
+ rgb.SetRed( KStartValue );
+ rgb.SetGreen( KStartValue );
+ rgb.SetBlue( KStartValue );
+
+ TRect rect;
+ for ( TInt x = 0; x < width; x += usedDrawStep )
+ {
+ iMaskGc->SetPenColor( rgb );
+ iMaskGc->SetBrushColor( rgb );
+ rect.iTl.iX = leftFadeEffectRect.iTl.iX + x;
+ rect.iTl.iY = 0;
+ rect.iBr.iX = rect.iTl.iX + usedDrawStep;
+ rect.iBr.iY = rect.iTl.iY + parentRect.Height();
+
+ iMaskGc->DrawRect( rect );
+ rgb.SetRed( rgb.Red() + usedFadeStep );
+ rgb.SetGreen( rgb.Green() + usedFadeStep );
+ rgb.SetBlue( rgb.Blue() + usedFadeStep );
+ }
+
+ iMaskGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iMaskGc->SetPenColor( KRgbBlack );
+ iMaskGc->SetBrushColor( KRgbBlack );
+ iMaskGc->DrawRect( TRect( parentRect.iTl.iX,
+ parentRect.iTl.iY,
+ leftFadeEffectRect.iTl.iX,
+ parentRect.iBr.iY ) );
+
+
+ iMaskGc->SetPenStyle( CGraphicsContext::ESolidPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+
+ KMaxFadeSteps = KEndValue - KStartValue;
+ usedFadeStep = 0;
+ usedDrawStep = 1;
+
+ if ( width < KMaxFadeSteps &&
+ width != 0 )
+ {
+ usedFadeStep = KMaxFadeSteps / width;
+ }
+ else
+ {
+ usedFadeStep = 1;
+ usedDrawStep = width / KMaxFadeSteps;
+ }
+
+ rgb.SetRed( KStartValue );
+ rgb.SetGreen( KStartValue );
+ rgb.SetBlue( KStartValue );
+
+ for ( TInt x = width - 1; x >= 0; x -= usedDrawStep )
+ {
+ iMaskGc->SetPenColor( rgb );
+ iMaskGc->SetBrushColor( rgb );
+ rect.iTl.iX = rightFadeEffectRect.iTl.iX + x;
+ rect.iTl.iY = 0;
+ rect.iBr.iX = rect.iTl.iX + usedDrawStep;
+ rect.iBr.iY = rect.iTl.iY + parentRect.Height();
+
+ iMaskGc->DrawRect( rect );
+ rgb.SetRed( rgb.Red() + usedFadeStep );
+ rgb.SetGreen( rgb.Green() + usedFadeStep );
+ rgb.SetBlue( rgb.Blue() + usedFadeStep );
+ }
+
+ iMaskGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iMaskGc->SetBrushColor( KRgbBlack );
+ iMaskGc->DrawRect( TRect( rightFadeEffectRect.iBr.iX,
+ parentRect.iTl.iY,
+ parentRect.iBr.iX,
+ parentRect.iBr.iY ) );
+ break;
+ }
+ case EEffectFadeOut:
+ case EEffectFadeIn:
+ {
+ TRgb fadeRgb;
+ fadeRgb.SetRed( iFadeInOutValue );
+ fadeRgb.SetGreen( iFadeInOutValue );
+ fadeRgb.SetBlue( iFadeInOutValue );
+ iMaskGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iMaskGc->SetPenColor( fadeRgb );
+ iMaskGc->SetBrushColor( fadeRgb );
+ iMaskGc->DrawRect( iEffectRect );
+
+ iMaskGc->SetPenStyle( CGraphicsContext::ENullPen );
+ iMaskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+ iMaskGc->SetPenColor( KRgbBlack );
+ iMaskGc->SetBrushColor( KRgbBlack );
+ iMaskGc->DrawRect( TRect( parentRect.iTl.iX,
+ parentRect.iTl.iY,
+ iEffectRect.iTl.iX,
+ parentRect.iBr.iY ) );
+ break;
+ }
+ case EEffectPause:
+ case EEffectNone:
+ case EEffectToggleScrolledTextTruncation:
+ case EEffectDefaultScroll:
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+
+CFbsBitmap* CAknTitlePaneLabel::TextAsBitmap()
+ {
+ if ( iEffect != EEffectNone )
+ {
+ return iBitmap;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+
+CFbsBitmap* CAknTitlePaneLabel::TextAsMask()
+ {
+ if ( iEffect != EEffectNone )
+ {
+ return iMask;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+
+void CAknTitlePaneLabel::HandleGainingForeground()
+ {
+ TRAP_IGNORE( InitTimerL( KScrollTimerDelay, KScrollTimerInterval ) );
+ }
+
+void CAknTitlePaneLabel::HandleLosingForeground()
+ {
+ CancelTimer();
+ }
+
+
+TInt CAknTitlePaneLabel::EffectEvent( TAny* aPtr )
+ {
+ static_cast<CAknTitlePaneLabel*> ( aPtr )->DoEffectEvent();
+ return ETrue;
+ }
+
+
+TBool CAknTitlePaneLabel::DoDefaultScrollEffectEvent()
+ {
+ TBool done( EFalse );
+ if ( !TextNeedsTruncation() )
+ {
+ iScrollStep = 0;
+ done = ETrue;
+ }
+
+ if ( iScrollDirectionBackwards )
+ {
+ iScrollStep = -ScrollStepInPixels();
+ if ( iScrollPosition == 0 )
+ {
+ // If text is at the other end, switch
+ // scrolling direction and continue.
+ iScrollDirectionBackwards = EFalse;
+ TRAP_IGNORE(
+ InitTimerL(
+ KScrollTimerDelayBeforeDirectionReversal,
+ KScrollTimerInterval ) ); // Make a littler longer delay at the ends
+ }
+ }
+ else
+ {
+ iScrollStep = ScrollStepInPixels();
+ if ( iScrollPosition + iScrollRect.Width() > iTextLength + iScrollRect.Width() / 10 )
+ {
+ // If text is at the other end, switch scrolling direction and continue
+ iScrollDirectionBackwards = ETrue;
+ TRAP_IGNORE(
+ InitTimerL(
+ KScrollTimerDelayBeforeDirectionReversal,
+ KScrollTimerInterval ) ); // Make a littler longer delay at the ends
+ }
+ }
+ iScrollPosition += iScrollStep;
+ return done;
+ }
+
+
+TBool CAknTitlePaneLabel::DoLoopScrollEffectEvent()
+ {
+ TBool done( EFalse );
+ if ( !TextNeedsTruncation() )
+ {
+ iScrollStep = 0;
+ done = ETrue;
+ }
+
+ iScrollStep = ScrollStepInPixels();
+ if ( iScrollPosition > iTextLength + iScrollRect.Width() / 10 )
+ {
+ // If text has scrolled away from screen, start again from the other end
+ iScrollPosition = -iScrollRect.Width();
+ }
+ iScrollPosition += iScrollStep;
+ return done;
+ }
+
+
+TBool CAknTitlePaneLabel::DoScrollOnceEffectEvent()
+ {
+ TBool done( EFalse );
+ if ( !TextNeedsTruncation() )
+ {
+ iScrollStep = 0;
+ done = ETrue;
+ }
+ else
+ {
+ iScrollStep = ScrollStepInPixels();
+ if ( iScrollPosition + iScrollRect.Width() > iTextLength + iScrollRect.Width() / 10 )
+ {
+ // If text is at the other end, continue with fade after timout
+ iScrollStep = 0;
+ done = ETrue;
+ }
+ }
+ iScrollPosition += iScrollStep;
+ return done;
+ }
+
+
+TBool CAknTitlePaneLabel::DoFadeInEffectEvent()
+ {
+ TBool done( EFalse );
+ if ( iEffectDuration )
+ {
+ TInt interval = iEffectDuration / KEndValue;
+
+ if ( interval < KMinInterval )
+ {
+ interval = KMinInterval;
+ iFadeInOutStep = iEffectDuration / KMinInterval;
+ }
+ else
+ {
+ iFadeInOutStep = 1;
+ }
+
+ if ( iFadeInOutStep < 1 )
+ {
+ iFadeInOutStep = 1;
+ }
+ if ( iFadeInOutStep > KEndValue )
+ {
+ iFadeInOutStep = KEndValue;
+ }
+
+ TRAP_IGNORE( InitTimerL( interval, interval ) );
+
+ iEffectDuration = 0;
+ iFadeInOutValue = 0; // start from fully invisible
+ }
+
+ if ( iFadeInOutValue + iFadeInOutStep > KEndValue )
+ {
+ iFadeInOutValue = KEndValue;
+ done = ETrue;
+ }
+ else
+ {
+ iFadeInOutValue += iFadeInOutStep;
+ }
+
+ return done;
+ }
+
+TBool CAknTitlePaneLabel::DoFadeOutEffectEvent()
+ {
+ TBool done( EFalse );
+ if ( iEffectDuration )
+ {
+ TInt interval = iEffectDuration / KEndValue;
+
+ if ( interval < KMinInterval )
+ {
+ interval = KMinInterval;
+ iFadeInOutStep = iEffectDuration / KMinInterval;
+ }
+ else
+ {
+ iFadeInOutStep = 1;
+ }
+
+ if ( iFadeInOutStep < 1 )
+ {
+ iFadeInOutStep = 1;
+ }
+ if ( iFadeInOutStep > KEndValue )
+ {
+ iFadeInOutStep = KEndValue;
+ }
+
+ TRAP_IGNORE( InitTimerL( interval, interval ) );
+
+ iEffectDuration = 0;
+ iFadeInOutValue = KEndValue; // start from fully visible
+ }
+
+ if ( iFadeInOutValue - iFadeInOutStep < 0 )
+ {
+ iFadeInOutValue = 0;
+ done = ETrue;
+ }
+ else
+ {
+ iFadeInOutValue -= iFadeInOutStep;
+ }
+
+ return done;
+ }
+
+
+TBool CAknTitlePaneLabel::DoPauseEffectEvent()
+ {
+ TBool done( EFalse );
+ if ( iEffectDuration )
+ {
+ TRAP_IGNORE( InitTimerL( iEffectDuration, iEffectDuration ) );
+ iEffectDuration = 0;
+ }
+ else
+ {
+ done = ETrue;
+ }
+ return done;
+ }
+
+
+TBool CAknTitlePaneLabel::DoToggleScrolledTextTruncationEffectEvent()
+ {
+ iScrollPosition = 0;
+ return ETrue;
+ }
+
+
+void CAknTitlePaneLabel::DoEffectEvent()
+ {
+ TBool done( EFalse );
+
+ switch ( iEffect )
+ {
+ case EEffectDefaultScroll:
+ case EEffectDefaultScrollWithFade:
+ done = DoDefaultScrollEffectEvent();
+ break;
+ case EEffectLoopScroll:
+ case EEffectLoopScrollWithFade:
+ done = DoLoopScrollEffectEvent();
+ break;
+ case EEffectFadeIn:
+ done = DoFadeInEffectEvent();
+ break;
+ case EEffectFadeOut:
+ done = DoFadeOutEffectEvent();
+ break;
+ case EEffectPause:
+ done = DoPauseEffectEvent();
+ break;
+ case EEffectScrollOnceWithFade:
+ done = DoScrollOnceEffectEvent();
+ break;
+ case EEffectToggleScrolledTextTruncation:
+ done = DoToggleScrolledTextTruncationEffectEvent();
+ break;
+ default:
+ iScrollStep = 0;
+ done = ETrue;
+ break;
+ }
+
+ // Draw text
+ DrawTextWithEffect();
+
+ // If done then process next effect
+ if ( done )
+ {
+ NextEffect();
+ }
+ }
+
+TBool CAknTitlePaneLabel::TextNeedsTruncation() const
+ {
+ if ( iTextLength > iScrollRect.Width() )
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+
+TBool CAknTitlePaneLabel::EffectEventsNeeded( TInt aEffect ) const
+ {
+ if ( aEffect == EEffectDefaultScroll ||
+ aEffect == EEffectDefaultScrollWithFade ||
+ aEffect == EEffectLoopScroll ||
+ aEffect == EEffectLoopScrollWithFade ||
+ aEffect == EEffectFadeOut ||
+ aEffect == EEffectFadeIn ||
+ aEffect == EEffectScrollOnceWithFade ||
+ aEffect == EEffectPause )
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+
+TBool CAknTitlePaneLabel::EffectBitmapsNeeded( TInt aEffect ) const
+ {
+ if ( aEffect == EEffectDefaultScroll ||
+ aEffect == EEffectDefaultScrollWithFade ||
+ aEffect == EEffectLoopScroll ||
+ aEffect == EEffectLoopScrollWithFade ||
+ aEffect == EEffectFadeOut ||
+ aEffect == EEffectFadeIn ||
+ aEffect == EEffectScrollOnceWithFade ||
+ aEffect == EEffectFadeToLeft ||
+ aEffect == EEffectFadeToRight )
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+
+TInt CAknTitlePaneLabel::ScrollStepInPixels() const
+ {
+ TInt stepInPixels = 2;
+
+ // Adjust scrolling speed according to screen size
+ TRect screenRect( iAvkonAppUi->ApplicationRect() );
+
+ TInt scale = KScaleMagicNumber;
+ if ( screenRect.Height() > screenRect.Width() )
+ {
+ scale = screenRect.Height();
+ }
+ else
+ {
+ scale = screenRect.Width();
+ }
+
+ stepInPixels = ( stepInPixels * scale ) / KScaleMagicNumber;
+
+ if ( stepInPixels < 1 )
+ {
+ stepInPixels = 1;
+ }
+
+ return stepInPixels;
+ }
+
+
+void CAknTitlePaneLabel::InitEffectQueueL()
+ {
+ if ( !iEffectQueue )
+ {
+ iEffectQueue = new (ELeave) CArrayFixFlat<SAknTitleLableEffect>( 2 );
+ }
+ iEffectQueue->Reset();
+ iNextEffectInEffectQueue = 0;
+ }
+
+
+void CAknTitlePaneLabel::AddToEffectQueueL( SAknTitleLableEffect aEffect )
+ {
+ if ( iEffectQueue )
+ {
+ iEffectQueue->AppendL( aEffect );
+ }
+ }
+
+
+void CAknTitlePaneLabel::ActivateEffectQueue()
+ {
+ if ( iEffectQueue && iEffectQueue->Count() > iNextEffectInEffectQueue )
+ {
+ iNextEffectInEffectQueue++;
+ SetTextEffect(
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iEffect,
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iEffectRect,
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iEffectDuration,
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iLabelRect,
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iTextLayout,
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iTextLayoutLine,
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iTitleText,
+ iEffectQueue->At( iNextEffectInEffectQueue - 1 ).iObserver);
+ }
+ }
+
+
+void CAknTitlePaneLabel::NextEffect()
+ {
+ CancelTimer();
+ ActivateEffectQueue();
+ }
+
+
+TInt CAknTitlePaneLabel::TextLength()
+ {
+ return iTextLength;
+ }
+
+
+void CAknTitlePaneLabel::HandleResourceChange( TInt aType )
+ {
+ CEikLabel::HandleResourceChange( aType );
+
+ if ( aType == KEikDynamicLayoutVariantSwitch )
+ {
+ CancelTimer();
+ TRAP_IGNORE( InitEffectQueueL() );
+ iEffect = 0;
+ }
+ }
+
+
+void CAknTitlePaneLabel::SetPictographInterface(
+ CAknPictographInterface& aInterface )
+ {
+ TRAP_IGNORE( EnablePictographsL( aInterface ) );
+ iPictographInterface = &aInterface;
+ }
+
+
+void CAknTitlePaneLabel::InvalidateText()
+ {
+ iTitleText = NULL;
+ }
+
+
+TBool CAknTitlePaneLabel::EffectQueueIsEmpty()
+ {
+ if ( iEffectQueue && iEffectQueue->Count() > 0 )
+ {
+ return EFalse;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+
+
+void CAknTitlePaneLabel::CreateScrollingTextL( const HBufC* aOriginalText )
+ {
+ delete iScrollingText;
+ iScrollingText = NULL;
+
+ if ( aOriginalText )
+ {
+ const CFont* fontUsed =
+ AknLayoutUtils::FontFromId( iTextLayoutLine.FontId() );
+ CFont::TMeasureTextInput input;
+ TInt textLength = fontUsed->MeasureText( *aOriginalText, &input );
+ // Add some safety margin ( must be at least this )
+ textLength = textLength + textLength / 2;
+ if ( textLength < Size().iWidth )
+ {
+ textLength = Size().iWidth;
+ }
+
+ iScrollingText = HBufC::NewL(
+ aOriginalText->Length() + KAknBidiExtraSpacePerLine );
+ TPtr ptr( iScrollingText->Des() );
+ ptr.Fill(' ');
+ AknBidiTextUtils::ConvertToVisualAndClip(
+ *aOriginalText,
+ ptr,
+ *iFont,
+ textLength,
+ textLength );
+
+ // Linefeed chars are always removed since this
+ // text should never be used with 2-line text.
+ ReplaceControlCharacters( iScrollingText, ETrue );
+ }
+ }
+
+
+void CAknTitlePaneLabel::ReplaceControlCharacters( HBufC* aText,
+ TBool aReplaceLinefeeds )
+ {
+ // Remove chars 0x00 to 0x1F and 0x2029 (Paragraph separator).
+ _LIT(KAknTitleLableStripListControlChars, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x2029");
+ // 0x0A (Newline) and 0x2029 (Paragraph separator) excluded.
+ _LIT(KAknTitleLableStripListControlCharsWithoutLinefeed, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F");
+
+ // Replace with space (0x20)
+ TChar replacementChar( 0x20 );
+
+ const TDesC& aChars = KAknTitleLableStripListControlChars;
+ const TDesC& aCharsWithoutLinefeed =
+ KAknTitleLableStripListControlCharsWithoutLinefeed;
+
+ TUint16* ptr = const_cast<TUint16*> ( aText->Ptr() );
+
+ TInt src = 0;
+ TInt srclength = aText->Length();
+ while( src < srclength )
+ {
+ TChar c( ptr[src] );
+ if ( aReplaceLinefeeds )
+ {
+ if ( aChars.LocateF( c ) != KErrNotFound )
+ {
+ ptr[src] = TUint16( replacementChar );
+ }
+ }
+ else
+ {
+ if ( aCharsWithoutLinefeed.LocateF( c ) != KErrNotFound )
+ {
+ ptr[src] = TUint16( replacementChar );
+ }
+ }
+ ++src;
+ }
+ }