idlehomescreen/xmluirendering/renderingplugins/xnnewstickerfactory/src/xnnewstickercontrol.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:40:49 +0200
changeset 0 f72a12da539e
child 1 5315654608de
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2002-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:  Text scrolling functionality.
*
*/


// INCLUDE FILES
#include <AknUtils.h>
#include <gulicon.h>
#include <AknsDrawUtils.h>
#include <AknBidiTextUtils.h>

#include "xnnewstickercontrol.h"
#include "xnnewstickeradapter.h"
#include "xnproperty.h"

// CONSTANTS
/**
* for the empty space in pixels between text and image.
*/
const TInt KGap = 10;

   
// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::CTitleData
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::CTitleData::CTitleData(TInt aLenghtInPixels) :
    iTitleIsSvg(EFalse), iTextLenghtInPixels(aLenghtInPixels)
    {
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::CTitleData::~CTitleData()
    {
    delete iText;
    delete iData;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::CTitleData::ConstructL(const TDesC& aTitle)
    {
    delete iText;
    iText = NULL;
    iText = aTitle.AllocL();
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::CTitleData::ConstructL(const TDesC8& aByteData)
    {
    iTitleIsSvg = ETrue;
    iData = aByteData.AllocL();
    iText = KNullDesC().AllocL();
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::CTitleData* CXnNewstickerControl::CTitleData::NewL(
                const TDesC& aTitle, TInt aLenghtInPixels)
    {
    CXnNewstickerControl::CTitleData* self =
            CXnNewstickerControl::CTitleData::NewLC(aTitle, aLenghtInPixels);
    CleanupStack::Pop(self);
    return self;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::CTitleData* CXnNewstickerControl::CTitleData::NewLC(
                const TDesC& aTitle, TInt aLenghtInPixels)
    {
    CXnNewstickerControl::CTitleData* self =
            new(ELeave) CXnNewstickerControl::CTitleData(aLenghtInPixels);
    CleanupStack::PushL(self);
    self->ConstructL(aTitle);
    return self;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::CTitleData* CXnNewstickerControl::CTitleData::NewL(
                const TDesC8& aByteData)
    {
    CXnNewstickerControl::CTitleData* self =
            CXnNewstickerControl::CTitleData::NewLC(aByteData);
    CleanupStack::Pop(self);
    return self;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::CTitleData* CXnNewstickerControl::CTitleData::NewLC(
                const TDesC8& aByteData)
    {
    CXnNewstickerControl::CTitleData* self =
            new(ELeave) CXnNewstickerControl::CTitleData();
    CleanupStack::PushL(self);
    self->ConstructL(aByteData);
    return self;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::TitleText
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
const TDesC& CXnNewstickerControl::CTitleData::TitleText()
    {
    return *iText;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::SetTitleText
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::CTitleData::SetTitleTextL(const TDesC& aTitle)
    {
    HBufC* newTitle = aTitle.AllocL();
    delete iText;
    iText = newTitle;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::TitleTextLengthInPixels
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CXnNewstickerControl::CTitleData::TitleTextLengthInPixels()
    {
    return iTextLenghtInPixels;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::SetTitleTextLengthInPixels
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::CTitleData::SetTitleTextLengthInPixels(TInt aLenghtInPixels)
    {
    iTextLenghtInPixels = aLenghtInPixels;    
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::IsSvgTitle
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CXnNewstickerControl::CTitleData::IsSvgTitle()
    {
    return iTitleIsSvg;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CTitleData::SvgTitleData
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
const TDesC8& CXnNewstickerControl::CTitleData::SvgTitleData()
    {
    return *iData;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CXnNewstickerControl
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::CXnNewstickerControl(CXnNewstickerAdapter* aAdapter) :     
    iFirstDrawingTitleIndex(0),
    iFirstDrawingOffset(0),
    iImageWidthInPixels(0),
    iCurrentTitleIndex(-1),
    iSeparatorimage(NULL),
    iSeparatorImageWidth(0),
    iFont(NULL),
    iTextBaseline(0),
    iTextColor(KRgbBlack),
    iUnderlining(EUnderlineOff),
    iStrikethrough(EStrikethroughOff),
    iIsWestern(ETrue),
    iAdapter(aAdapter),
    iTextAlignment(ELayoutAlignLeft)
    {
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::ConstructL()
    {
    if(AknLayoutUtils::LayoutMirrored())
        {
    	iIsWestern = EFalse;
        iTextAlignment = ELayoutAlignRight;
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl* CXnNewstickerControl::NewL(CXnNewstickerAdapter* aAdapter)
    {
    CXnNewstickerControl* self = new(ELeave)CXnNewstickerControl(aAdapter);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();    
    return self;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::~CXnNewstickerControl()
// Destructor.
// -----------------------------------------------------------------------------
//
CXnNewstickerControl::~CXnNewstickerControl()
    {
    iTitles.ResetAndDestroy();
    delete iSeparatorimage;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetScrollAmount
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::SetScrollAmount(TInt aScrollAmount)
    {
    iSpeed = aScrollAmount;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetNewstickerRect
// Set visible rect.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::SetNewstickerRect(TRect& aContentRect)
    {
    if(iContentRect != aContentRect)
        {
        iContentRect = aContentRect;
        iTextBaseline = iContentRect.Height() / 2 + iFont->AscentInPixels() / 2;
        SetBeginningState();
        for(TInt i = 0; i < iTitles.Count(); i++)
            {
            if(!iTitles[i]->IsSvgTitle())
                {
                TInt textWidth = iFont->TextWidthInPixels(
                    iTitles[i]->TitleText());
                iTitles[i]->SetTitleTextLengthInPixels(textWidth);
                }
            }
        CalculateTextFitInNewstickerRect();        
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::IsWestern
// Returns ETrue if western layout is used, otherwise EFalse is returned.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CXnNewstickerControl::IsWestern()
    {
    return iIsWestern;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::AppendTitleL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::AppendTitleL(const TDesC& aTitle)
    {
    TInt textWidth = iFont->TextWidthInPixels(aTitle);
    CTitleData* title = CTitleData::NewLC(aTitle, textWidth);
    iTitles.AppendL(title);
    CleanupStack::Pop(title);
    
    CalculateTextFitInNewstickerRect();    

    // if this is the first item
    if(iTitles.Count() == 1) 
        {
        iCurrentTitleIndex = 0;
        iAdapter->StartL();    
        }
    }

// ---------------------------------------------------------
// CXnNewstickerControl::InsertTitleL
// ---------------------------------------------------------
//
void CXnNewstickerControl::InsertTitleL(const TDesC& aTitle, TInt aIndex)
    {
    TInt textWidth = iFont->TextWidthInPixels(aTitle);
    CTitleData* title = CTitleData::NewLC(aTitle, textWidth);
    iTitles.InsertL(title, aIndex);
    CleanupStack::Pop(title);

    
    CountIndexAfterInsertL(aIndex);
    CalculateTextFitInNewstickerRect();    
    }

// ---------------------------------------------------------
// CXnNewstickerControl::UpdateTitleL
// ---------------------------------------------------------
//
void CXnNewstickerControl::UpdateTitleL(const TDesC& aTitle, TInt aIndex)
    {
    if ( aIndex >= 0 && aIndex < iTitles.Count() )
        {
        CTitleData* titleData = iTitles[aIndex];    
        TInt textWidth = iFont->TextWidthInPixels(aTitle);
        titleData->SetTitleTextL(aTitle);
        titleData->SetTitleTextLengthInPixels(textWidth);
        CalculateTextFitInNewstickerRect();
        }
    else
        {
        AppendTitleL(aTitle);
        }
    }

// ---------------------------------------------------------
// CXnNewstickerControl::DeleteTitle
// ---------------------------------------------------------
//
void CXnNewstickerControl::DeleteTitleL(TInt aIndex)
    {
    TInt count = iTitles.Count();
    if (aIndex >= 0 && aIndex < count)
        {
        // If the last item will be deleted
        if(count == 1)
            {
            iAdapter->StopL();
            iFirstDrawingTitleIndex = GetNextTitleWithContent( 0 );
            SetBeginningState();
            iCurrentTitleIndex = -1;
            }
        if (aIndex == iFirstDrawingTitleIndex)
            {
            // If this happens to be the last item in the list
            if(aIndex == count - 1)
                {
                iFirstDrawingTitleIndex = GetNextTitleWithContent( 0 );
                }
            SetBeginningState();
            iCurrentTitleIndex = iFirstDrawingTitleIndex;
            }
            
        //  Check if the title was deleted before the current title
        else if (aIndex < iFirstDrawingTitleIndex)
            {
            iCurrentTitleIndex--;
            iFirstDrawingTitleIndex = GetNextTitleWithContent( iFirstDrawingTitleIndex-1, ETrue);
            }
        UpdateTitleL(KNullDesC, aIndex);
        CalculateTextFitInNewstickerRect();        
        }
    }

// ---------------------------------------------------------
// CXnNewstickerControl::CurrentTitleIndex
// ---------------------------------------------------------
//
TInt CXnNewstickerControl::CurrentTitleIndex()
    {
    return iCurrentTitleIndex;
    }

// ---------------------------------------------------------
// CXnNewstickerControl::Title
// ---------------------------------------------------------
//
const TDesC& CXnNewstickerControl::Title(TInt aIndex)
    {
    if (aIndex < 0 || aIndex > iTitles.Count())
        {
        return KNullDesC;
        }

    if (iTitles[aIndex]->IsSvgTitle())
        {
        return KNullDesC;
        }

    return iTitles[aIndex]->TitleText();
    }

// ---------------------------------------------------------
// CXnNewstickerControl::SetSeparatorImageL
// ---------------------------------------------------------
//
TInt CXnNewstickerControl::SetSeparatorImageL(CGulIcon* aIcon)
    {
    CFbsBitmap* bitmap = aIcon->Bitmap();
    if(AknIconUtils::IsMifIcon(bitmap))
        {
        delete iSeparatorimage;
        iSeparatorimage = aIcon;
        TInt maxHeight = iContentRect.Height();
        TSize size = TSize(maxHeight, maxHeight);        
        AknIconUtils::SetSize(bitmap, size, EAspectRatioPreservedAndUnusedSpaceRemoved);
        iSeparatorImageWidth = bitmap->SizeInPixels().iWidth + KGap;
        return KErrNone;
        }
    else
        {
        iSeparatorimage = NULL;
        return KErrNotSupported;
        }
    }

// ---------------------------------------------------------
// CXnNewstickerControl::ClearTitles
// ---------------------------------------------------------
//
void CXnNewstickerControl::ClearTitles()
    {
    TRAP_IGNORE(iAdapter->StopL());
    iFirstDrawingTitleIndex = 0;
    SetBeginningState();
    iCurrentTitleIndex = -1;
    // Don't delete just clear the contents
    for( TInt i = 0; i < iTitles.Count(); ++i )
        {
        TRAP_IGNORE( UpdateTitleL( KNullDesC, i ) );
        }
    iTextFitInNewstickerRect = EFalse;
    }

// ---------------------------------------------------------
// CXnNewstickerControl::AppendSvgTitleL
// ---------------------------------------------------------
//
void CXnNewstickerControl::AppendSvgTitleL(const TDesC8& aByteData)
    {
    CTitleData* title = CTitleData::NewLC(aByteData);
    iTitles.AppendL(title);
    CleanupStack::Pop(title);
    
    // if this is the first item
    if(iTitles.Count() == 1) 
        {
        iCurrentTitleIndex = 0;
        iAdapter->StartL();
        }
    }

// ---------------------------------------------------------
// CXnNewstickerControl::InsertSvgTitleL
// ---------------------------------------------------------
//
void CXnNewstickerControl::InsertSvgTitleL(const TDesC8& aByteData, TInt aIndex)
    {
    CTitleData* title = CTitleData::NewLC(aByteData);
    iTitles.InsertL(title, aIndex);
    CleanupStack::Pop(title);
    CountIndexAfterInsertL(aIndex);
    }

// ---------------------------------------------------------
// CXnNewstickerControl::CurrentSvgTitle
// ---------------------------------------------------------
//
const TDesC8& CXnNewstickerControl::CurrentSvgTitle()
    {
    CTitleData* title = iTitles[iFirstDrawingTitleIndex];
    //  Is it SVG title
    if (title->IsSvgTitle())
        {
        //  Yes, advance the title index
        iFirstDrawingTitleIndex++;
        if (iFirstDrawingTitleIndex >= iTitles.Count())
            {
            iFirstDrawingTitleIndex = 0;
            }

        //  Return the data
        return title->SvgTitleData();
        }

    //  Not svg title, return empty desc
    return KNullDesC8;
    }

// ---------------------------------------------------------
// CXnNewstickerControl::TitleCount
// ---------------------------------------------------------
//
TInt CXnNewstickerControl::TitleCount() const
    {
    return iTitles.Count();
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::MoveToNext
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::MoveToNextL()
    {
    //  If there are no titles, don't do anything.
    if (!IsVisibleTitles())
        {
        return ;
        }
    // Skip notification of the first title
    if ( iCurrentTitleIndex != GetNextTitleWithContent( 0 ) )
        {
        iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleScrolled);
        }
    // Don't report the last TitleToScroll in case the scroll ended
    if ( iAdapter->CurrentState() != CXnNewstickerAdapter::EScrollEnded )
        {    
        iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleToScroll);
        }
    iAdapter->TitleScrolled(iFirstDrawingTitleIndex);
    if (iAdapter->CurrentState() == CXnNewstickerAdapter::EAnimation)
        {
        iCurrentTitleIndex = GetNextTitleWithContent( iCurrentTitleIndex + 1 );
        iFirstDrawingTitleIndex = iCurrentTitleIndex;
        }
    else
        {
        iCurrentTitleIndex = GetNextTitleWithContent( iFirstDrawingTitleIndex + 1);
        iFirstDrawingTitleIndex = iCurrentTitleIndex;
        }

    //  Check that we are still in range
    if (iFirstDrawingTitleIndex >= iTitles.Count() || iFirstDrawingTitleIndex < 0)
        {
        iFirstDrawingTitleIndex = GetNextTitleWithContent( 0 );
        iCurrentTitleIndex = iFirstDrawingTitleIndex;
        }

    SetBeginningState();
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::MoveToFirstL
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::MoveToFirstL()
    {
    //  If there are no titles, don't do anything.
    if (!IsVisibleTitles())
        {
        return ;
        }
    // Something already scrolling, report scroll done
    if ( iAdapter->CurrentState() == CXnNewstickerAdapter::EText )
        {
        iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleScrolled);
        iAdapter->TitleScrolled(iFirstDrawingTitleIndex);
        }
       
    TInt start = 0; // iIsWestern ? 0 : (iTitles.Count() - 1);
    
    iCurrentTitleIndex = GetNextTitleWithContent( start );
    iFirstDrawingTitleIndex = iCurrentTitleIndex;
    iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleToScroll);
    SetBeginningState();
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::MoveToLastL
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::MoveToLastL()
    {
    //  If there are no titles, don't do anything.
    if (!IsVisibleTitles())
        {
        return ;
        }
    // Something already scrolling, report scroll done
    if ( iAdapter->CurrentState() == CXnNewstickerAdapter::EText )
        {
        iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleScrolled);
        iAdapter->TitleScrolled(iFirstDrawingTitleIndex);
        }
    
    TInt start = iTitles.Count() - 1; // iIsWestern ? (iTitles.Count() - 1) : 0;
    
    iCurrentTitleIndex = GetNextTitleWithContent( start, ETrue );
    iFirstDrawingTitleIndex = iCurrentTitleIndex;
    iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleToScroll);
    SetBeginningState();
    }
// -----------------------------------------------------------------------------
// CXnNewstickerControl::MoveToPrev
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::MoveToPrevL()
    {
    //  If there are no titles, don't do anything.
    if (!IsVisibleTitles())
        {
        return ;
        }
    
    iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleScrolled);

    if (iAdapter->CurrentState() == CXnNewstickerAdapter::EAnimation)
        {
        iCurrentTitleIndex = GetNextTitleWithContent( iCurrentTitleIndex - 1, ETrue );        
        iFirstDrawingTitleIndex = iCurrentTitleIndex;
        }
    else
        {
        iFirstDrawingTitleIndex = GetNextTitleWithContent( iFirstDrawingTitleIndex - 1, ETrue );
        iCurrentTitleIndex = iFirstDrawingTitleIndex;
        }
    //  Check that we are still in range
    if (iFirstDrawingTitleIndex >= iTitles.Count() || iFirstDrawingTitleIndex < 0)
        {
        iFirstDrawingTitleIndex = GetNextTitleWithContent( iTitles.Count() - 1, ETrue );
        iCurrentTitleIndex = iFirstDrawingTitleIndex;
        }
    
    iAdapter->ReportNewstickerEventL(XnPropertyNames::action::trigger::name::KTitleToScroll);
    SetBeginningState();
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::MoveToCurrent
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::MoveToCurrent()
    {
    //  If there are no titles, don't do anything.
    if (!IsVisibleTitles())
        {
        return ;
        }

    iFirstDrawingTitleIndex = iCurrentTitleIndex;
    SetBeginningState();    
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CountIndexAfterInsert
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::CountIndexAfterInsertL(TInt aIndex)
    {
    //  Check if the new title was inserted before the first drawing title
    if (aIndex <= iFirstDrawingTitleIndex)
        {
        iCurrentTitleIndex++;
        iFirstDrawingTitleIndex++;
        }
        
    // if this is the first item
    if(iTitles.Count() == 1 && GetNextTitleWithContent( 0 ) == 0) 
        {
        iCurrentTitleIndex = 0;
        iFirstDrawingTitleIndex = 0;
        iAdapter->StartL();
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetFont
// -----------------------------------------------------------------------------
void CXnNewstickerControl::SetFont(CFont* aFont)
    {
    if(iFont != aFont)
        {
        for(TInt i = 0; i < iTitles.Count(); i++)
            {
            if(!iTitles[i]->IsSvgTitle())
                {
                TInt textWidth = aFont->TextWidthInPixels(
                    iTitles[i]->TitleText());
                iTitles[i]->SetTitleTextLengthInPixels(textWidth);
                }
            }
        iFont = aFont;
        iTextBaseline = iContentRect.Height() / 2 + iFont->AscentInPixels() / 2;
        CBitmapContext* gc = iAdapter->BufferGc();
        if(gc)
            {
            gc->UseFont(aFont);
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetTextColor
// -----------------------------------------------------------------------------
void CXnNewstickerControl::SetTextColor(TRgb aColor)
    {
    iTextColor = aColor;
    CBitmapContext* gc = iAdapter->BufferGc();
    if(gc)
        {
        gc->SetPenColor(iTextColor);
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetTextUnderlineStyle
// -----------------------------------------------------------------------------
void CXnNewstickerControl::SetTextUnderlineStyle(TFontUnderline aStyle)
    {
    iUnderlining = aStyle;
    CBitmapContext* gc = iAdapter->BufferGc();
    if(gc)
        {
        gc->SetUnderlineStyle(iUnderlining);        
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetTextUnderlineStyle
// -----------------------------------------------------------------------------
void CXnNewstickerControl::SetTextStrikethroughStyle(TFontStrikethrough aStyle)
    {
    iStrikethrough = aStyle;
    CBitmapContext* gc = iAdapter->BufferGc();
    if(gc)
        {
        gc->SetStrikethroughStyle(iStrikethrough);        
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::PrepareToDrawL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::PrepareToDrawLtrL()
    {
    CBitmapContext* gc = iAdapter->BufferGc();
    const CFbsBitmap* background = iAdapter->BackgroundBitmap();
    if(!gc || !background || !IsVisibleTitles() )
        {
        return;
        }
    iFirstDrawingTitleIndex = GetNextTitleWithContent( iFirstDrawingTitleIndex );
    if ( iFirstDrawingTitleIndex < 0 )
        {
        return;
        }
    if (iTitles[iFirstDrawingTitleIndex]->IsSvgTitle())
        {
        //  Show SVG title
        iAdapter->ShowSvgL();
        
    	// Just in case, draw background to d-buffer
        gc->BitBlt(TPoint(0,0), background);
        return;
        }

    CGraphicsContext::TTextAlign alignment = TextAlignment();
    if ( iTextFitInNewstickerRect || 
         iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EAlternate && iTitles.Count() == 1 )
        {
        iAdapter->StopL();
        SetBeginningState();
        }
    
	TInt drawingPos(-iFirstDrawingOffset);

	// At first, draw background
    gc->BitBlt(TPoint(0,0), background);
    TInt textLeft = iTitles[iFirstDrawingTitleIndex]->TitleTextLengthInPixels() - 
        iFirstDrawingOffset;
    TInt drawingTitleIndex = iFirstDrawingTitleIndex;
    TInt drawingOffset(0);

	// Main drawing loop. This loop runs as long as drawing area is not filled
    // if Scroll behaviour is slide, then short text drawn only once.
    FOREVER
        {
        TRect clipRect(TPoint(drawingPos,0), TPoint(iContentRect.Width(), iContentRect.Height()));
        if ( iTextFitInNewstickerRect )
            {
            clipRect.SetWidth( clipRect.Width()-drawingPos);
            }
        // if the rest text fits into visible area
     	if (textLeft <= iContentRect.Width() - drawingOffset)
     	    {
            gc->DrawText(iTitles[drawingTitleIndex]->TitleText(), 
                   clipRect,
                   iTextBaseline,
                   alignment);

     	    TInt drawnLength = iTitles[drawingTitleIndex]->TitleTextLengthInPixels() + KGap;
            drawingPos += drawnLength;
     	    drawingOffset = drawingPos;
            
            // Update title index, if needed
     	    drawingTitleIndex++;
     	    if(drawingTitleIndex >= iTitles.Count())
     	        {
     	        drawingTitleIndex = 0;
     	        if ( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::ESlide || iTextFitInNewstickerRect )
     	            {
     	            // what a dirty code!
     	            break;
     	            }
     	        }
            if(iSeparatorimage)
                {
                textLeft = 0;
                }
            else
                {
                if (iTitles[drawingTitleIndex]->IsSvgTitle())
                    {
                    return;
                    }
                else
                    {
                    textLeft = iTitles[drawingTitleIndex]->TitleTextLengthInPixels(); 
                    }
                }
     	    }
        else 
            {
            // Clip the text if needed in alternate mode
            if  ( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EAlternate )
                {
                HBufC* title = iTitles[drawingTitleIndex]->TitleText().AllocLC();
                TPtr titlePtr = title->Des();
                TInt maxLength = iContentRect.Width();
                AknBidiTextUtils::ConvertToVisualAndClipL(
                        titlePtr, *iFont, maxLength, maxLength );                              
                gc->DrawText( titlePtr, clipRect, iTextBaseline, alignment );
                CleanupStack::PopAndDestroy( title );
                }
            else
                {
                gc->DrawText(iTitles[drawingTitleIndex]->TitleText(), 
                        clipRect,
                        iTextBaseline,
                        alignment);
            
                }            
     	    break;
            }
            
        if(iSeparatorimage)
     	    {
            TInt imageLeft = iSeparatorImageWidth - KGap;
            
            // if the rest of the image fits into visible area
 	        if (imageLeft <= iContentRect.Width() - drawingOffset)
 	            {
 	            gc->BitBltMasked(TPoint(drawingPos, 0), iSeparatorimage->Bitmap(), 
 	                TRect(TPoint(0,0), 
 	                iSeparatorimage->Bitmap()->SizeInPixels()), iSeparatorimage->Mask(), ETrue); 
                drawingPos += iSeparatorImageWidth;
     	        drawingOffset = drawingPos;
                textLeft = iTitles[drawingTitleIndex]->TitleTextLengthInPixels();
                if (iTitles[drawingTitleIndex]->IsSvgTitle())
                    {
                    return;
                    }
 	            }
            else 
                {
 	            gc->BitBltMasked(TPoint(drawingPos, 0), iSeparatorimage->Bitmap(), 
 	                TRect(TPoint(0,0), iSeparatorimage->Bitmap()->SizeInPixels()), 
 	                iSeparatorimage->Mask(), ETrue); 
                break;
                }
     	    }

        if( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EAlternate || 
			iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate )
            {
            break;
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::PrepareToDrawRtlL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::PrepareToDrawRtlL()
    {
    CBitmapContext* gc = iAdapter->BufferGc();
    const CFbsBitmap* background = iAdapter->BackgroundBitmap();
    if(!gc || !background || !IsVisibleTitles() )
        {
        return;
        }
    if (iTitles[iFirstDrawingTitleIndex]->IsSvgTitle())
        {
        //  Show SVG title
        iAdapter->ShowSvgL();
        
    	// Just in case, draw background to d-buffer
        gc->BitBlt(TPoint(0,0), background);
        return;
        }

    CGraphicsContext::TTextAlign alignment = TextAlignment();
    if ( iTextFitInNewstickerRect || 
         iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EAlternate && iTitles.Count() == 1 )
        {
        SetBeginningState();
        iAdapter->StopL();
        }
    
	// At first, draw background
    gc->BitBlt(TPoint(0,0), background);
    
    TInt textLeft = iFirstDrawingOffset - 
        iTitles[iFirstDrawingTitleIndex]->TitleTextLengthInPixels();
    if(textLeft >= iContentRect.Width() )
        {
        textLeft = 0;
        }
    TInt drawingTitleIndex = iFirstDrawingTitleIndex;
    TInt drawingOffset(iContentRect.iBr.iX);
    
    TRect clipRect(TPoint(0,0), TPoint(iFirstDrawingOffset, iContentRect.Height()));
    TInt clipWidth = clipRect.Width();
	// Main drawing loop. This loop runs as long as drawing area is not filled
    FOREVER
        {
     	// if the rest text fits into visible area
     	if (textLeft <= drawingOffset)
     	    {
     	    HBufC* title = iTitles[drawingTitleIndex]->TitleText().AllocLC();
     	    TPtr titlePtr = title->Des();

     	    // convert to visual, do not clip
     	    TInt maxLength = iTitles[drawingTitleIndex]->TitleTextLengthInPixels();
     	    AknBidiTextUtils::ConvertToVisualAndClipL( titlePtr, *iFont,
     	                                               maxLength, maxLength );
   
            gc->DrawText( titlePtr, clipRect, iTextBaseline, alignment );
            CleanupStack::PopAndDestroy( title );

     	    TInt drawnLength = iTitles[drawingTitleIndex]->TitleTextLengthInPixels() + KGap;
            clipWidth -= drawnLength;
            clipRect.SetWidth(clipWidth);
            drawingOffset = clipRect.iBr.iX;

            // Update title index
     	    drawingTitleIndex++;
     	    if(drawingTitleIndex >= iTitles.Count())
     	        {
     	        drawingTitleIndex = 0;
                if ( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::ESlide || iTextFitInNewstickerRect)
                    {
                    // what a dirty code!
                    break;
                    }
     	        }
            if(iSeparatorimage)
                {
                textLeft = 0xfff;
                }
            else
                {
                if (iTitles[drawingTitleIndex]->IsSvgTitle())
                    {
                    return;
                    }
                else
                    {
                    textLeft = iTitles[drawingTitleIndex]->TitleTextLengthInPixels(); 
                    }
                }
     	    }
        else 
            {
            // Clip the text if needed in alternate mode
            if  ( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EAlternate )
                {
                HBufC* title = iTitles[drawingTitleIndex]->TitleText().AllocLC();
                TPtr titlePtr = title->Des();
                TInt maxLength = iContentRect.Width();
                AknBidiTextUtils::ConvertToVisualAndClipL(
                        titlePtr, *iFont, maxLength, maxLength );                              
                gc->DrawText( titlePtr, clipRect, iTextBaseline, alignment );
                CleanupStack::PopAndDestroy( title );
                }
            else
                {
                gc->DrawText(iTitles[drawingTitleIndex]->TitleText(), clipRect, 
                        iTextBaseline, alignment);
                }
     	    break;
            }

        if(iSeparatorimage)
     	    {
            TInt imageLeft = iSeparatorImageWidth - KGap;
            
            // if the rest of the image fits into visible area
 	        if (imageLeft <= drawingOffset)
 	            {
 	            gc->BitBltMasked(TPoint(clipRect.iBr.iX - imageLeft, 0), 
 	                iSeparatorimage->Bitmap(), TRect(TPoint(0,0), 
 	                iSeparatorimage->Bitmap()->SizeInPixels()), 
 	                iSeparatorimage->Mask(), ETrue);                
                clipWidth -= iSeparatorImageWidth;
                clipRect.SetWidth(clipWidth);
                drawingOffset = clipRect.iBr.iX;                
                textLeft = iTitles[drawingTitleIndex]->TitleTextLengthInPixels();
                if (iTitles[drawingTitleIndex]->IsSvgTitle())
                    {
                    return;
                    }
 	            }
            else 
                {
 	            gc->BitBltMasked(TPoint(clipRect.iBr.iX - imageLeft, 0), 
 	                iSeparatorimage->Bitmap(), TRect(TPoint(0,0), 
 	                iSeparatorimage->Bitmap()->SizeInPixels()), 
 	                iSeparatorimage->Mask(), ETrue); 
                break;
                }
     	    }
     	    
        if( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EAlternate || 
			iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate )     	    
            {
            break;
            }     	    
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::DoScrollL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::DoScrollL()
    {
    //  If there are no titles, don't do anything.
    if( !IsVisibleTitles() || iFirstDrawingTitleIndex < 0 )
        {
        return;
        }
    
    iAdapter->DrawNow();
    
    if( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScroll ||
        iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::ESlide ||
		( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate &&
		  !CalculateCurrentTextFitInNewstickerRect() ) )
        {    
        iAdapter->SetTimerToScrolltime();             
        iFirstDrawingOffset += iSpeed; // advance text
        TInt titleLen = iTitles[iFirstDrawingTitleIndex]->TitleTextLengthInPixels() + 
            iSeparatorImageWidth;

        // if 100% (or more) has been drawn update...
        if ((iIsWestern && iFirstDrawingOffset >= titleLen) ||
            (!iIsWestern && iFirstDrawingOffset - titleLen >= iContentRect.Width()))
            {
            iAdapter->TitleScrolled(iFirstDrawingTitleIndex);
            iFirstDrawingTitleIndex = GetNextTitleWithContent( iFirstDrawingTitleIndex + 1);
            if(iFirstDrawingTitleIndex >= iTitles.Count())
     	        {
     	        iFirstDrawingTitleIndex = GetNextTitleWithContent( 0 );
                if (iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::ESlide )
                    {
                    if ( iIsWestern )
                        {
                        iFirstDrawingOffset = -(iContentRect.iBr.iX-iContentRect.iTl.iX-KGap);
                        }
                    else
                        {
                        iFirstDrawingOffset = 0;
                        }
                    }
                else
                    {
                    iFirstDrawingOffset -= titleLen + KGap;
                    }
     	        }
            else
                {
                iFirstDrawingOffset -= titleLen + KGap;
                }
            iCurrentTitleIndex = iFirstDrawingTitleIndex;

            if( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate &&
		        CalculateCurrentTextFitInNewstickerRect() )
                {
                MoveToNextL();
                }
            }
        // but if less than 100% and more than 75% has been drawn, update only current title index.
        else if (((iIsWestern && iFirstDrawingOffset >= titleLen * 0.75) || 
                  (!iIsWestern && iFirstDrawingOffset - titleLen >= iContentRect.iBr.iX * 0.75)) &&
                   iFirstDrawingTitleIndex == iCurrentTitleIndex)
            {
            iCurrentTitleIndex++;
     	    if(iCurrentTitleIndex >= iTitles.Count())
     	        {
     	        iCurrentTitleIndex = 0;
     	        }
     	    iCurrentTitleIndex = GetNextTitleWithContent( iCurrentTitleIndex );

            if( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate &&
		        CalculateCurrentTextFitInNewstickerRect() )
                {
                MoveToNextL();
                }
            }
        }
    else if( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate &&
		     CalculateCurrentTextFitInNewstickerRect() )
        {
        iAdapter->SetTimerToDisplaytime();
        MoveToNextL();
        }
    else
        {
        MoveToNextL();
        }        
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::Draw
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::Draw()
    {
    if( IsVisibleTitles() > 0 ) 
        {
        if( iIsWestern )
            {
            TRAP_IGNORE( PrepareToDrawLtrL() );
            }
        else
            {
            TRAP_IGNORE( PrepareToDrawRtlL() );
            }
        }    
    else
        {
        CBitmapContext* gc = iAdapter->BufferGc();
        const CFbsBitmap* background = iAdapter->BackgroundBitmap();
        if ( gc && background )
            {            
            gc->BitBlt(TPoint(0,0), background);
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::DrawStatic
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::DrawStatic()
    {
    // draw to buffer gc
    CBitmapContext* gc = iAdapter->BufferGc();
    const CFbsBitmap* background = iAdapter->BackgroundBitmap();
    if( !gc || !background || !IsVisibleTitles() )
        {
        return;
        }
    gc->BitBlt( TPoint(0,0), background );
    
    // Get the last title
    TInt index = GetNextTitleWithContent( iTitles.Count() - 1, ETrue );
    const TDesC& title = Title( index );
    
    // truncate text if needed
    HBufC* visualText = HBufC::New(title.Length() + KAknBidiExtraSpacePerLine);
    if (visualText)
        {
        TPtr visualTextPtr(visualText->Des());
        TInt maxLength = iContentRect.Width();
        AknBidiTextUtils::ConvertToVisualAndClip(
                     title, visualTextPtr, *iFont, maxLength, maxLength );
            
        TRect blitRect( 0, 0, iContentRect.Width(), iContentRect.Height() );
        gc->DrawText( *visualText, blitRect, iTextBaseline, TextAlignment() );
        delete visualText;
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetBeginningState
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::SetBeginningState()
    {
    iFirstDrawingOffset = 0;
    if(!iIsWestern)
        {
        iFirstDrawingOffset = iContentRect.Width();
        }
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetScrollLooping
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::SetScrollLooping( TBool aLoop )
    {
    iScrollLooping = aLoop;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::ScrollLooping
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CXnNewstickerControl::ScrollLooping()
    {
    return iScrollLooping;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::TextFitInNewstickerRect
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CXnNewstickerControl::TextFitInNewstickerRect()
    {
    return iTextFitInNewstickerRect; 
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CalculateTextFitInNewstickerRect
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CXnNewstickerControl::CalculateTextFitInNewstickerRect()
    {
    if ( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::ESlide &&
         iTitles.Count() == 1 )
        {
        const TInt count = iTitles.Count();
        TInt textWidth=0;
        const TInt rectWidth = iContentRect.Width();
        for (TInt i=0; i<count && textWidth<rectWidth;i++)
            {
            textWidth += iTitles[i]->TitleTextLengthInPixels();
            }
        iTextFitInNewstickerRect = (textWidth<rectWidth);
        }
    else
        {
        iTextFitInNewstickerRect = EFalse;
        }
    return iTextFitInNewstickerRect;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::CalculateCurrentTextFitInNewstickerRect
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CXnNewstickerControl::CalculateCurrentTextFitInNewstickerRect()
    {
    if ( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate )
        {
        const TInt count = iTitles.Count();
        TInt textWidth=0;
        const TInt rectWidth = iContentRect.Width();
        if( iCurrentTitleIndex < count )
            {
            textWidth = iTitles[iCurrentTitleIndex]->TitleTextLengthInPixels();
            }
        return ( textWidth < rectWidth );
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::SetTextAlignment
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnNewstickerControl::SetTextAlignment(TInt aAlignment)
    {
    iTextAlignment = aAlignment;
    }

// -----------------------------------------------------------------------------
// CXnNewstickerControl::TextAlignment
// if title fits to the drawing rect and scrolling behaviour is ESlide then 
// use alignment value 
// if scroll behaviour is alternate then use alignment value
// otherwise return ELeft in western and ERight on AH
// -----------------------------------------------------------------------------
//
CGraphicsContext::TTextAlign CXnNewstickerControl::TextAlignment()
    {
    CGraphicsContext::TTextAlign alignment = iIsWestern ? CGraphicsContext::ELeft : CGraphicsContext::ERight;
    
    if ( iTextFitInNewstickerRect || iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EAlternate ||
         ( iAdapter->ScrollBehaviour() == CXnNewstickerAdapter::EScrollAlternate && 
           CalculateCurrentTextFitInNewstickerRect() ) )
        {
        switch( iTextAlignment )
            {
            default:
            case ELayoutAlignLeft:
                alignment = CGraphicsContext::ELeft;
                break;
            case ELayoutAlignRight:
                alignment = CGraphicsContext::ERight;
                break;
            case ELayoutAlignCenter:
                alignment = CGraphicsContext::ECenter;
                break;
            }
        }
    return alignment;
    }

TInt CXnNewstickerControl::GetNextTitleWithContent( TInt aStartSearch, TBool aBackwards )
    {
    TInt dir = 1;
    if ( aBackwards )
        {
        dir = -1;
        }
    for( TInt i = aStartSearch; i < iTitles.Count() && i >= 0; i += dir )
        {
        if ( iTitles[i]->TitleTextLengthInPixels() != 0 )
            {
            return i;
            }
        }
    return aStartSearch;
    }

TBool CXnNewstickerControl::IsVisibleTitles()
    {
    for( TInt i = 0; i < iTitles.Count() ; ++i )
        {
        if ( iTitles[i]->TitleTextLengthInPixels() != 0 )
            {
            return ETrue;
            }
        }
    return EFalse;
    }


//  End of File