internetradio2.0/uicontrolssrc/irstationinformationdisplay.cpp
author Pat Downey <patd@symbian.org>
Tue, 18 May 2010 11:36:57 +0100
changeset 4 3f2d53f144fe
parent 0 09774dfdd46b
permissions -rw-r--r--
Merge docml changeset with recent Nokia delivery.

/*
* Copyright (c) 2007-2008 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:  Control that displays current station information
*
*/


#include <aknsconstants.h>
#include <aknutils.h>
#include <biditext.h>

#include <alf/alfcontrolgroup.h>
#include <alf/alfdecklayout.h>
#include <alf/alfenv.h>
#include <alf/alfevent.h>
#include <alf/alflayout.h>
#include <alf/alfgridlayout.h>
#include <alf/alftextvisual.h>
#include <alf/alfviewportlayout.h>


//#include "vrdebug.h"
#include "irstationinformationdata.h"
#include "irstationinformationdisplay.h"
#include "irdebug.h"

// Tag to identify a text visual with.
_LIT8( KVRTagTextVisual, "KVRTagTextVisual" );
// Tag to identify a layout visual with.
_LIT8( KVRTagLayout, "KVRTagLayout" );

// Time in milliseconds to spend animating the displays moving in and out of the screen.
const TInt KVRDisplayFadeTime = 400;

// This is context-sensitive per scrollable visual, so the actual start time depends on the additional application logic.
const TInt KVRScrollDelayTime = 1000;
// Time in milliseconds to snooze after scrolling has completed.
// This is used to halt the scrolling at the very end for a period of time, making it visually more pleasing.
const TInt KVRScrollSnoozeTime = 1000;

// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CIRStationInformationDisplay* CIRStationInformationDisplay::NewL( CAlfEnv& aEnv, 
								TInt aControlGroupId,CAlfLayout* aParentLayout )
    {
    
    CIRStationInformationDisplay* self = new ( ELeave ) 
    						CIRStationInformationDisplay( *aParentLayout );
    CleanupStack::PushL( self );
    self->ConstructL( aEnv, aControlGroupId, aParentLayout );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
CIRStationInformationDisplay::CIRStationInformationDisplay( CAlfLayout& aParentLayout )
    : iParentAnchorLayout( aParentLayout )
    {
    }

// ---------------------------------------------------------------------------
// Second-phase constructor.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::ConstructL( CAlfEnv& aEnv, TInt aControlGroupId, 
												CAlfLayout* aParentLayout )
    {
    CAlfControl::ConstructL( aEnv );

    
    // Base layout is created here so the control can be as independent from the parent layout as possible.
    iBaseLayout = CAlfDeckLayout::AddNewL( *this, aParentLayout );
    
    aEnv.ControlGroup( aControlGroupId ).AppendL( this ); // Takes ownership. No leaving code allowed after this call.
    iLandScapSetFalg=EFalse;    
    
    }

// <TUNING TEMP>
CIRStationInformationDisplay::~CIRStationInformationDisplay()
    {
    Env().CancelCustomCommands( this );
    iRdsDataText.Close();
    }


// ---------------------------------------------------------------------------
// Sets the displayed data.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::SetDisplayedDataL( const CIRStationInformationData& aData )
    {
    FadeOutDisplay( aData );
    CreateDisplayL( aData );
    FadeInDisplay( aData );
    }

// ---------------------------------------------------------------------------
// Sets the RDS data display which is used only in landscape.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::SetDisplayOrientation( TBool aLandscape )
    {
    if ( iLandscape && !aLandscape )
         {
         // Going from landscape to portrait: Remove separate display for RDS data.
        iParentAnchorLayout.Remove( iRdsDataLayout, 0 );
         }
    iLandscape = aLandscape;
    }

TIRFadeStyle  CIRStationInformationDisplay::FadeStyle()
    {
    return iFadeStyle;
    }
// ---------------------------------------------------------------------------
// Sets the RDS data.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::RdsDataReceivedL( const TDesC& aRdsData )
    {

    if ( iRdsData )
        {
        TBool rdsDataExisted = iRdsData->Text().Length() ? ETrue : EFalse;
        TAlfTimedValue opacity( iRdsData->Opacity().ValueNow() );

        if ( aRdsData.Length() )
            {
            if ( rdsDataExisted )
                {
                if( iRdsDataText != aRdsData )
                    {
                iRdsDataText.Close();
                iRdsDataText.CreateL( aRdsData );
                 // Fade out previous text.
                opacity.SetTarget( 0.0f, KVRDisplayFadeTime );
                FadeVisual( *iRdsData, opacity );
                // Displaying RDS text will be started after fade out is done.
                Env().Send( 
                	TAlfCustomEventCommand( EIRCustomEventVisualFadeOutCompleted, this ),
                	 KVRDisplayFadeTime );
                    }

                }
            else
                {
                iRdsDataText.Close();
                iRdsDataText.CreateL( aRdsData );
                iRdsData->SetTextL( iRdsDataText );
                // Start to display RDS text.
                DisplayRdsDataL();
                // Fade in.
                if ( !iLandscape )
                    {
                    // Orientation is portrait.
                    iLayout->SetRowsL( iLayout->RowCount() + 1 );
                    iLayout->Reorder( *iRdsDataLayout, iLayout->RowCount() - 1, 
                    				KVRDisplayFadeTime );
                    iRdsData->SetFlag( EAlfVisualFlagManualPosition );
                    iName->SetFlag( EAlfVisualFlagManualPosition );
                    iLayout->UpdateChildrenLayout( KVRDisplayFadeTime );
                    iRdsData->ClearFlag( EAlfVisualFlagManualPosition );
                    iName->ClearFlag( EAlfVisualFlagManualPosition );
                    }
                opacity.SetTarget( 1.0f, KVRDisplayFadeTime );
                FadeVisual( *iRdsData, opacity );
                }
            }
        else // RDS data has been lost.
            {
            }
        }
    }


// ---------------------------------------------------------------------------
// From class CAlfControl.
// Called when a visual's layout has been updated.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::VisualLayoutUpdated( CAlfVisual& aVisual )
    {
    CAlfControl::VisualLayoutUpdated( aVisual );

    // TO be done  Special handling for scrolling required while changing orientation...
    }

// ---------------------------------------------------------------------------
// From class CAlfControl.
// Event handler.
// ---------------------------------------------------------------------------
//
TBool CIRStationInformationDisplay::OfferEventL( const TAlfEvent& aEvent )
    {
    TBool eventHandled = EFalse;
    
    if ( aEvent.IsCustomEvent() )
        {

        
        switch ( aEvent.CustomParameter() )
            {
            case EIRCustomEventDisplayFadeInCompleted:
                {
                 // When a display has faded in, its position will be handled by the framework and text scrolling should start.
                reinterpret_cast<CAlfGridLayout*>( aEvent.CustomEventData() )->ClearFlag( 
                												EAlfVisualFlagManualPosition );
                // Start to display name.to be changed
                iNameMarqueeClet.StartL( KVRScrollDelayTime, KVRScrollSnoozeTime );
                // Start to display RDS data.
                DisplayRdsDataL();
                eventHandled = ETrue;
                break;
                }
            case EIRCustomEventDisplayFadeOutCompleted:
                {
                // When display has faded out old layout needs to be destroyed
                reinterpret_cast<CAlfGridLayout*>
                			( aEvent.CustomEventData() )->RemoveAndDestroyAllD();
                eventHandled = ETrue;
                break;
                }
             case EIRCustomEventVisualFadeOutCompleted:
                {
                iRdsData->SetTextL( iRdsDataText );
                if ( iRdsDataText.Length() )
                    {
                    // Start to display RDS data.
                    DisplayRdsDataL();
                    // Fade in.
                    TAlfTimedValue opacity( iRdsData->Opacity().ValueNow() );
                    opacity.SetTarget( 1.0f, KVRDisplayFadeTime );
                    FadeVisual( *iRdsData, opacity );
                    }
                eventHandled = ETrue;
                break;
                }
            default:
                break;
            }
        }

    return eventHandled;
    }

// ---------------------------------------------------------------------------
// Creates a new display that is used to show the supplied data.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::CreateDisplayL( const CIRStationInformationData& aData )
    {

    iFadeStyle = aData.FadeDirectionality();
    iLayout = CAlfGridLayout::AddNewL( *this, 1, 1, iBaseLayout );

    // A separate layout has to be created for the station's index and its name as 
    // the index has to be a separate entity from the name due to scrolling issues.
    // This layout will contain both of these texts, but only the name can scroll.
    // Index is never scrolled, and both fields are center-aligned to the display.
    iNameIndexLayout = CAlfGridLayout::AddNewL( *this, 2, 1, iLayout );
    iNameIndexLayout->SetTagL( KVRTagLayout );

    iIndex = CAlfTextVisual::AddNewL( *this, iNameIndexLayout );
    iIndex->SetTextL( aData.Index() );
    iIndex->SetTagL( KVRTagTextVisual );
    iIndex->SetOpacity( 0.0f );
    iIndex->SetColor( KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG6 );
    iIndex->SetStyle( EAlfTextStyleSmall );
    iIndex->SetAlign( EAlfAlignHLocaleMirrored, EAlfAlignVCenter ); // Right-aligned normally, left-aligned in mirrored.

    CAlfViewportLayout* nameViewport = CAlfViewportLayout::AddNewL( *this, iNameIndexLayout );
    nameViewport->SetFlag( EAlfVisualFlagLayoutUpdateNotification );
    nameViewport->SetTagL( KVRTagLayout );
    
    iName = CAlfTextVisual::AddNewL( *this, nameViewport );
    iName->SetTextL( aData.Name() );
    iName->SetTagL( KVRTagTextVisual );
    iName->SetOpacity( 0.0f );
    iName->SetColor( KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG6 );
    iName->SetStyle( EAlfTextStyleSmall );
    iName->SetAlign( EAlfAlignHLocale, EAlfAlignVCenter );
    iName->SetWrapping( CAlfTextVisual::ELineWrapTruncate );

    // Forces the viewport marquee to use a linear interpolation style.
    TAlfTimedPoint point( 0.0f, 0.0f );
    point.SetStyle( EAlfTimedValueStyleLinear );
    iName->SetPos( point );


    if ( AknLayoutUtils::LayoutMirrored() ) 
        {
        // In mirrored layouts the name is on the left side.

        iNameIndexLayout->Reorder( *nameViewport, 0, 0 );
        }

    // Decides the correct directionality for the scroll.
    iNameMarqueeClet.Set( *nameViewport, *iName );

// This is added due to possible scrolling issues.
    // Grid layout (iRdsDataLayout) for RDS data is added due to possible scrolling issues.
    // For some reason scrolling won’t work without this extra grid layout.
    if ( iLandscape )
        {
        // Landscape: Create own separate display for RDS data.
        iLandScapSetFalg=ETrue;
        iRdsDataLayout = CAlfGridLayout::AddNewL( *this, 1, 1, &iParentAnchorLayout );
        }
    else
        {
        // Portrait: RDS data will be displayed below the station information.
        iRdsDataLayout = CAlfGridLayout::AddNewL( *this, 1, 1, iLayout );
        }
    iRdsDataLayout->SetTagL( KVRTagLayout );

    // RDS data view port.
    CAlfViewportLayout* rdsDataViewport = CAlfViewportLayout::AddNewL( *this, iRdsDataLayout );
    rdsDataViewport->SetFlag( EAlfVisualFlagLayoutUpdateNotification );
    rdsDataViewport->SetTagL( KVRTagLayout );

    // RDS data text visual.
    iRdsDataText.Close();
    iRdsDataText.CreateL( aData.RdsPsName() );
    iRdsData = CAlfTextVisual::AddNewL( *this, rdsDataViewport );
    iRdsData->SetTextL( iRdsDataText );
    iRdsData->SetTagL( KVRTagTextVisual );
    iRdsData->SetOpacity( 0.0f );
    iRdsData->SetColor( KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG6 );
    iRdsData->SetStyle( EAlfTextStyleSmall );
    iRdsData->SetWrapping( CAlfTextVisual::ELineWrapManual );
    iRdsData->SetPos( point );

    // Set RDS data.
    iRdsDataMarqueeClet.Set( *rdsDataViewport, *iRdsData );
    // RDS data scrolling style is continuous scrolling.
    iRdsDataMarqueeClet.SetScrollStyle( TIRMarqueeClet::EIRScrollStyleLoop );

    // Determining the initial row count for the grid and reordering its elements.
    TInt rowCount = 1;//1
	if ( iIndex->Text().Length() || iName->Text().Length() )
        {
        //rowCount++;
        }
    if ( iRdsData->Text().Length() && !iLandscape  )
        {
        rowCount++;
        // RDS data will always be the last element in the grid.
        iLayout->Reorder( *iRdsDataLayout, rowCount - 1, 0 );//3rd 0
        }


    iLayout->SetRowsL( rowCount );
    // Calculates the layout for station index and name by using grid weights.
    // Two cases are considered:
    //      1) Index and name fit on the screen without scrolling.
    //         In this case they are center-aligned on the screen.
    //      2) Index and name do not fit on the screen, scrolling must be used.
    //         In this case the index is aligned to either to the left or right,
    //         depending on the used locale, and the name will scroll as a separate
    //         entity.
    
    
    TInt layoutWidth = static_cast<TInt>( iNameIndexLayout->Size().ValueNow().iX );

    TInt indexWidth = iIndex->TextExtents().iWidth;
    TInt nameWidth = iName->TextExtents().iWidth;
    
    if ( layoutWidth < indexWidth + nameWidth )
        {
        nameWidth = layoutWidth - indexWidth;
        }
    else
        {
        TInt overflow = layoutWidth - indexWidth - nameWidth;

        // Overlowing part of the layout is split evenly between the index and the name.
        indexWidth += overflow / 2;
        nameWidth += overflow / 2;
        }
    
    RArray<TInt> weights;
    CleanupClosePushL( weights );
    if ( AknLayoutUtils::LayoutMirrored() )
        {
        weights.AppendL( nameWidth );
        weights.AppendL( indexWidth );
        }
    else
        {
        weights.AppendL( indexWidth );
        weights.AppendL( nameWidth );
        }
    iNameIndexLayout->SetColumnsL( weights );
    CleanupStack::PopAndDestroy( &weights );
    iLayout->UpdateChildrenLayout();

    }

// ---------------------------------------------------------------------------
// Fades in the current display.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::FadeInDisplay( const CIRStationInformationData& aData )
    {
    if ( iLayout )
        {
        TAlfRealPoint size = iLayout->Size().ValueNow();
        TAlfRealPoint pos = iLayout->Pos().ValueNow();
        
        TAlfTimedValue opacity( 0.0f );
        opacity.SetStyle( EAlfTimedValueStyleDecelerate );

        TInt fadeTime = KVRDisplayFadeTime;
        
        TAlfTimedPoint point( pos.iX, pos.iY, KVRDisplayFadeTime );
        point.SetStyle( EAlfTimedValueStyleDecelerate );
        
        switch ( aData.FadeDirectionality() )
            {
            case EIRFadeUnknown:
                point.iX.SetValueNow( pos.iX );
                point.iY.SetValueNow( pos.iY );
                break;
            case EIRFadeLeftToRight:
                point.iX.SetValueNow( pos.iX - size.iX );
                point.iY.SetValueNow( pos.iY );
                break;
            case EIRFadeRightToLeft:
                point.iX.SetValueNow( pos.iX + size.iX );
                point.iY.SetValueNow( pos.iY );
                break;
            case EIRFadeTopToBottom:
                point.iX.SetValueNow( pos.iX );
                point.iY.SetValueNow( pos.iY - size.iY );
                break;
            case EIRFadeBottomToTop:
                point.iX.SetValueNow( pos.iX );
                point.iY.SetValueNow( pos.iY + size.iY );
                break;
            case EIRFadeNoFade:
                fadeTime = 0;
                point.iX.SetValueNow( pos.iX );
                point.iY.SetValueNow( pos.iY );
                point.SetTarget( pos, fadeTime );
                break;
            default:
                break;
            }

        opacity.SetTarget( 1.0f, fadeTime );

        iLayout->SetFlag( EAlfVisualFlagManualPosition );
        iLayout->SetPos( point );
        FadeLayout( *iLayout, opacity );

        if ( iLandscape )
            {
            // If the orientation is landscape the RDS text layout needs to be visible regardless
            // how we got in this point, be it startup, orientation change, skin change or something
            // else. This needs to be done here because RDS text may have already been available
            // and if there is not a change in RDS text then there is no notification to update
            // RDS text which leads to not showing the available RDS text
            Env().Send( TAlfCustomEventCommand( EIRCustomEventVisualFadeOutCompleted, this ), 0 );
            }
        Env().Send( TAlfCustomEventCommand( EIRCustomEventDisplayFadeInCompleted, this,
        			 reinterpret_cast<TInt>( iLayout ) ), 0 );
        }
    }

// ---------------------------------------------------------------------------
// Fades out the current display.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::FadeOutDisplay( const CIRStationInformationData& aData )
    {
    if ( iLayout )
        {
        TAlfRealPoint size = iLayout->Size().ValueNow();
        TAlfRealPoint pos = iLayout->Pos().ValueNow();

        TAlfTimedValue opacity( iLayout->Opacity().ValueNow() );
        opacity.SetStyle( EAlfTimedValueStyleAccelerate );
        opacity.SetTarget( 0.0f, KVRDisplayFadeTime );
        
        TAlfTimedPoint point( pos.iX, pos.iY );
        point.SetStyle( EAlfTimedValueStyleAccelerate );

        TAlfRealPoint target = iLayout->Pos().Target();

        TInt fadeTime = KVRDisplayFadeTime;
        
        switch ( aData.FadeDirectionality() )
            {
            case EIRFadeUnknown:
                point.SetTarget( TAlfRealPoint( target.iX, target.iY ), KVRDisplayFadeTime );
                break;
            case EIRFadeLeftToRight:
                point.SetTarget( TAlfRealPoint( target.iX + size.iX, target.iY ),
                				 KVRDisplayFadeTime );
                break;
            case EIRFadeRightToLeft:
                point.SetTarget( TAlfRealPoint( -size.iX, target.iY ), KVRDisplayFadeTime );
                break;
            case EIRFadeTopToBottom:
                point.SetTarget( TAlfRealPoint( target.iX, target.iY + size.iY ),
                								 KVRDisplayFadeTime );
                break;
            case EIRFadeBottomToTop:
                point.SetTarget( TAlfRealPoint( target.iX, target.iY - size.iY ), 
                								KVRDisplayFadeTime );
                break;
            case EIRFadeNoFade:
                fadeTime = 0;
                point.SetTarget( TAlfRealPoint( target.iX, target.iY ), fadeTime );
                opacity.SetTarget( 0.0f, fadeTime );
                break;
            default:
                break;
            }

        iLayout->SetFlag( EAlfVisualFlagManualPosition );
        iLayout->SetPos( point );
        FadeLayout( *iLayout, opacity );

        Env().CancelCustomCommands( this, EIRCustomEventDisplayFadeInCompleted );
        if ( iRdsDataLayout && iLayout != iRdsDataLayout->Layout() )
            {

            // In landscape orientation RDS data is not part of the station information data and no fading out is needed.
            // RDS data can be removed and destroyed at once.
            Env().Send( TAlfCustomEventCommand( EIRCustomEventDisplayFadeOutCompleted, this,
            			 reinterpret_cast<TInt>( iRdsDataLayout ) ), 0 );

            }
        Env().Send( TAlfCustomEventCommand( EIRCustomEventDisplayFadeOutCompleted, this,
        			 reinterpret_cast<TInt>( iLayout ) ), fadeTime );
        }

    // Saved pointers to the visuals will later on be invalid, as they will get deleted in the custom event handler.
    
    iLayout = NULL;
    iNameIndexLayout = NULL;
    iRdsDataLayout = NULL;
    iName = NULL;
    iIndex = NULL;

    iRdsData = NULL;
    }

// ---------------------------------------------------------------------------
// Fades a single visual.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::FadeVisual( CAlfVisual& aVisual,const TAlfTimedValue& aOpacity)
    {
    TAlfTimedValue opacity( aVisual.Opacity().ValueNow() );
    opacity.SetTarget( aOpacity.Target(), aOpacity.TimeToTargetinMilliSeconds() );
    
    if ( aVisual.Tag() == KVRTagTextVisual )
        {
        CAlfTextVisual& visual = static_cast<CAlfTextVisual&>( aVisual );
        if ( visual.Text().Length() )
            {
            visual.SetOpacity( opacity );
            visual.SetShadowOpacity( opacity );
            }
        }
    else
        {
        aVisual.SetOpacity( opacity );
        }
    }

// ---------------------------------------------------------------------------
// Fades all visuals contained within the supplied layout.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::FadeLayout( CAlfLayout& aLayout, const TAlfTimedValue& aOpacity)
    {
    for ( TInt i = 0; i < aLayout.Count(); i++ )
        {
        CAlfVisual& visual = aLayout.Visual( i );
        if ( visual.Tag() == KVRTagLayout )
            {
            FadeLayout( static_cast<CAlfLayout&>( visual ), aOpacity );
            }
        else
            {
            FadeVisual( visual, aOpacity );
            }
        }
        
    }



// ---------------------------------------------------------------------------
// Starts to display RDS data.
// ---------------------------------------------------------------------------
//
void CIRStationInformationDisplay::DisplayRdsDataL()
    {
    // Set default alignment.
    if ( iLandscape )
        {
        //iRdsData->SetAlign( EAlfAlignHLocale, EAlfAlignVCenter )
        iRdsData->SetAlign( EAlfAlignHCenter, EAlfAlignVCenter );

        }
    else
        {
        iRdsData->SetAlign( EAlfAlignHCenter, EAlfAlignVCenter );
        }
    // Start displaying.
    iRdsDataMarqueeClet.StartL( KVRScrollDelayTime + KVRDisplayFadeTime);
    }