/*
* Copyright (c) 1997-2009 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:
*
*/


#include <eiklbi.h>
#include <eiklbm.h>
#include <badesca.h>
#include <eikpanic.h>
#include <w32std.h>		// Is this really needed?
#include <gdi.h>
#include <gulutil.h>
#include <eiksfont.h>
#include <eikenv.h>
#include <gulcolor.h>
#include <coemain.h>		// Is this really needed?
#include <eiklbd.h>
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
#include <aknlistloadertfx.h>
#include <aknlistboxtfxinternal.h>
#endif //RD_UI_TRANSITION_EFFECTS_LIST
#include <aknappui.h>

#include "laflbi.h"
#include "laflbx.h"
#include "akntrace.h"

const TUint KListItemDrawerAllowedFlags = 0x3fff;

const TInt KDefaultMarkColumnWidth = 10;
const TInt KDefaultMarkGutter = 2;

//
// class TListItemProperties
//

EXPORT_C TListItemProperties::TListItemProperties()
	: iFlags(0) 
	{}

//
// class CListItemDrawer
//

EXPORT_C MAknsControlContext *CListItemDrawer::SkinBackgroundControlContext() const
	{
	if (iData)
		{
		return iData->SkinBackgroundControlContext();
		}
	return NULL;
	}
EXPORT_C void CListItemDrawer::SetSkinEnabledL(TBool aEnabled)
	{
	if(iData)
		{
		iData->SetSkinEnabledL(aEnabled);
		}
	}

/**
 * Sets the item drawer flags to aFlags, masking off all
 * but the lower 3 bits.
 */
EXPORT_C void CListItemDrawer::SetFlags(TInt aFlags)
    {
    // Pressed down highlight is blocked out if
    // single click mode is enabled
    if ( aFlags & EPressedDownState 
           &&  iFlags & ESingleClickEnabled )
        {
        aFlags &= ~EPressedDownState;
        }
    
    // do not raise EDrawWholeBackground unless ENativeImplementation is set
    if ( ( aFlags & EDrawWholeBackground ) 
            && !( iFlags & ENativeImplementation ) )
        {
        aFlags &= ~EDrawWholeBackground;
        }
    
    iFlags |= aFlags; 
    iFlags &= KListItemDrawerAllowedFlags;
    }

/**
 * Clears the item drawer flags aFlags, masking off all
 * but the lower 3 bits.
 */
EXPORT_C void CListItemDrawer::ClearFlags(TInt aFlags)
	{iFlags&=(~aFlags); iFlags&=KListItemDrawerAllowedFlags;}


EXPORT_C CListItemDrawer::CListItemDrawer()
    : iFlags(0)
    {
    _AKNTRACE_FUNC_ENTER;
	iMarkColumnWidth = KDefaultMarkColumnWidth;
	iMarkGutter = KDefaultMarkGutter;
	CEikonEnv* eikEnv=CEikonEnv::Static();
	iMarkColor = eikEnv->Color(EColorControlText);
	iBackColor = eikEnv->Color(EColorControlBackground);
	iHighlightedBackColor = eikEnv->Color(EColorControlHighlightBackground);
    if ( iAvkonAppUi && 
         iAvkonAppUi->IsSingleClickCompatible() )
        {
        SetFlags( ESingleClickEnabled | EDisableMarquee );
        }
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C CListItemDrawer::~CListItemDrawer()
    {
    _AKNTRACE_FUNC_ENTER;
    delete iData;
    _AKNTRACE_FUNC_EXIT;
    }

/**
 * Sets the font storage data for the item drawer to aFontStorage and transfers ownership.
 *
 * @since ER5U
 */
EXPORT_C void CListItemDrawer::SetData(CListBoxData* aData)
    {
    iData=aData;
    }

/**
 * Returns the font for the item at index aItemIndex. Returns NULL if no font storage data 
 * has been set.
 *
 * @since ER5U
 */
EXPORT_C CFont* CListItemDrawer::Font(TInt aItemIndex) const
    {
    if (iData)
        return iData->Font( Properties( aItemIndex ) );
    else
		return NULL;
    }

/**
 * Returns the properties of the item at index aItemIndex.
 * 
 * @since ER5U
 */
EXPORT_C TListItemProperties CListItemDrawer::Properties(TInt /*aItemIndex*/) const
    {
	TListItemProperties properties;
	properties.SetColor(iTextColor);
    return properties;
    }

EXPORT_C void CListItemDrawer::ResetGc() const
	{
	_AKNTRACE_FUNC_ENTER;
	iGc->SetPenStyle(CGraphicsContext::ESolidPen);
	iGc->SetBrushStyle(CGraphicsContext::ENullBrush);
	iGc->SetBrushColor(iBackColor);
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C void CListItemDrawer::SetGc(CWindowGc* aGc)
	{
	_AKNTRACE_FUNC_ENTER;
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
	// assert that aGc is not null
    MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iGc );
    if ( transApi )
        {
        if ( aGc )
            {
            transApi->SetGc( *aGc );
            }
        }
    else
        {
#endif //RD_UI_TRANSITION_EFFECTS_LIST
    	iGc = aGc;

#ifdef RD_UI_TRANSITION_EFFECTS_LIST
        }

#endif //RD_UI_TRANSITION_EFFECTS_LIST
    _AKNTRACE_FUNC_EXIT;
	}

EXPORT_C void CListItemDrawer::SetMarkColumnWidth(TInt aWidthInPixels)
	{
	iMarkColumnWidth = aWidthInPixels;
	}

EXPORT_C void CListItemDrawer::SetMarkGutter(TInt aGapInPixels)
	{
	iMarkGutter = aGapInPixels;
	}

EXPORT_C TInt CListItemDrawer::MarkColumn() const
	{
	return iMarkColumnWidth;
	}

EXPORT_C TInt CListItemDrawer::MarkGutter() const
	{
	return iMarkGutter;
	}

EXPORT_C void CListItemDrawer::SetItemCellSize(const TSize& aSizeInPixels)
	{
	iItemCellSize = aSizeInPixels;
	}

EXPORT_C TSize CListItemDrawer::ItemCellSize() const
    {
    return iItemCellSize;
    }

EXPORT_C void CListItemDrawer::SetViewRect(const TRect& aRect)
	{
	iViewRect = aRect;
	}

EXPORT_C CWindowGc* CListItemDrawer::Gc() const
	{
	return(iGc);
	}

/**
 * Returns the rectangle occupied by the matcher cursor in the text aMatchableText. The pixel position of
 * the rectangle is determined by specifying the character position of the cursor in the text aCharPos and the
 * vertical position of the item cell aItemCellYPos. The size of the rectangle can be determined by giving the 
 * index of the current item aCurrentItemIndex.
 *
 * Returns the rectangle occupied by the item drawer by default.
 */
EXPORT_C TRect CListItemDrawer::MatcherCursorRect(const TDesC& /*aMatchableText*/, TInt /*aCharPos*/, TInt /*aItemCellYPos*/, TInt /*aCurrentItemIndex*/ ) const
	{
	// derived classes that deal with text and want to support incremental matching in
	// listboxes need to redefine this function
	return TRect();
	}

/**
 * Returns the ascent of the matcher cursor for the item at index aCurrentItemIndex determined from the 
 * ascent of the font used for that item.
 *
 * Returns 0 by default.
 */
EXPORT_C TInt CListItemDrawer::MatcherCursorAscent( TInt /*aCurrentItemIndex*/ ) const
	{
	// derived classes that deal with text and want to support incremental matching in
	// listboxes need to redefine this function
	return 0;
	}

EXPORT_C void CListItemDrawer::DrawItem(TInt aItemIndex, TPoint aItemRectPos, TBool aItemIsSelected, TBool aItemIsCurrent, TBool aViewIsEmphasized, TBool aViewIsDimmed) const
	{
	_AKNTRACE_FUNC_ENTER;
	TRect actualItemRect(aItemRectPos, iItemCellSize);

#ifdef RD_UI_TRANSITION_EFFECTS_LIST
    MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iGc );
    if ( transApi )
        {
        transApi->BeginRedraw( MAknListBoxTfxInternal::EListItem, actualItemRect, aItemIndex );
        }
#endif //RD_UI_TRANSITION_EFFECTS_LIST

	DrawActualItem(aItemIndex, actualItemRect, aItemIsCurrent, aViewIsEmphasized, aViewIsDimmed, aItemIsSelected);
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
    if ( transApi )
        {
        transApi->EndRedraw( MAknListBoxTfxInternal::EListItem, aItemIndex );
        }
#endif //RD_UI_TRANSITION_EFFECTS_LIST
    _AKNTRACE_FUNC_EXIT;
	}

EXPORT_C void CListItemDrawer::DrawItemMark(TBool /*aItemIsSelected*/, TBool /*aViewIsDimmed*/, const TPoint& /*aItemRectPos*/) const
	{
        // not used in S60
	}

EXPORT_C void CListItemDrawer::ClearRect(const TRect& aRect) const
	{
	if (iGc)
		{
		iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
		iGc->SetBrushColor(iBackColor);
		iGc->SetPenStyle(CGraphicsContext::ENullPen);
		iGc->DrawRect(aRect);
		ResetGc();
		}
	}

EXPORT_C TInt CListItemDrawer::ItemWidthInPixels(TInt /*aItemIndex*/) const
	{
	return(0);
	}

EXPORT_C void CListItemDrawer::SetDrawMark(TBool aDrawMark)
	{
	if ( aDrawMark )
		SetFlags( EDrawMarkSelection );
	else
		ClearFlags( EDrawMarkSelection );
	}

EXPORT_C TSize CListItemDrawer::MinimumCellSize() const
	{
	return TSize(0, 0);
	}

EXPORT_C void CListItemDrawer::SetSymbolFont(const CFont* aFont)
	{
	iSymbolFont = aFont;
	}

EXPORT_C void CListItemDrawer::SetVerticalInterItemGap(TInt aGapInPixels)
	{
	iVerticalInterItemGap = aGapInPixels;
	}

EXPORT_C TInt CListItemDrawer::VerticalInterItemGap() const
	{
	return iVerticalInterItemGap;
	}

EXPORT_C void CListItemDrawer::SetupGc(TInt aItemIndex) const
    {
    if (iData)
        {
        iData->SetupGc(Properties(aItemIndex),*iGc);
        }
    }

EXPORT_C TAny* CListItemDrawer::Reserved_1()
	{
	return NULL;
	}

EXPORT_C void CListItemDrawer::DrawFrame(CWindowGc& aGc,const TRect& aRect,TInt aFlags) const
	{
	LafListItemDrawer::TLidColors colors(iTextColor,iBackColor,iHighlightedTextColor,
	iHighlightedBackColor,iDimmedTextColor,iDimmedBackColor,iMarkColor);

	LafListItemDrawer::DrawFrame(aGc,aRect,aFlags,colors);
	}

//
// class CTextListItemDrawer
//

EXPORT_C CTextListItemDrawer::CTextListItemDrawer()
	{
	_AKNTRACE_FUNC_ENTER;
	iItemMarkPos = -1;
	iItemMarkReplacement.Set(KNullDesC);
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C CTextListItemDrawer::~CTextListItemDrawer()
	{
	_AKNTRACE_FUNC_ENTER;
	iItemMarkPos = -1;
	iItemMarkReplacement.Set(KNullDesC);
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C CTextListItemDrawer::CTextListItemDrawer(MTextListBoxModel* aTextListBoxModel,const CFont* aFont)
	: iModel(aTextListBoxModel), iFont(aFont),
 	iItemMarkPos(-1),
 	iItemMarkReplacement(KNullDesC)
	{
	_AKNTRACE_FUNC_ENTER;
	CEikonEnv* eikEnv=CEikonEnv::Static();
	iTextColor = eikEnv->Color(EColorControlText); // KDefaultLbxTextColor
	iHighlightedTextColor = eikEnv->Color(EColorControlHighlightText); // KDefaultLbxHighlightedTextColor
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C void CTextListItemDrawer::ConstructL(const CFont* aFont /*, CEikListBox* aOwnerListBox*/)
    {
    _AKNTRACE_FUNC_ENTER;
    CListBoxData* data=new(ELeave) CListBoxData();
    CleanupStack::PushL(data);
    data->ConstructL(aFont);
    CleanupStack::Pop(); // data
    SetData(data);
    _AKNTRACE_FUNC_EXIT;
	}

EXPORT_C void CTextListItemDrawer::ResetGc() const
	{
	_AKNTRACE_FUNC_ENTER;
	CListItemDrawer::ResetGc();
	iGc->SetPenColor(iTextColor);
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C void CTextListItemDrawer::SetGc(CWindowGc* aGc)
    {
    _AKNTRACE_FUNC_ENTER;
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
    // assert that aGc is not null
    MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iGc );
    if ( transApi )
        {
        if ( aGc )
            {
            transApi->SetGc( *aGc );
            }
        }
    else
        {
#endif //RD_UI_TRANSITION_EFFECTS_LIST
        iGc = aGc;
#ifdef RD_UI_TRANSITION_EFFECTS_LIST
        }

#endif //RD_UI_TRANSITION_EFFECTS_LIST
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C TRect CTextListItemDrawer::MatcherCursorRect(const TDesC& aMatchableText,
        TInt aCharPos, TInt aItemCellYPos, TInt aCurrentItemIndex ) const
	{
    // iFont replaced with Font(currentItem)
	_AKNTRACE_FUNC_ENTER;
	TPoint cursorPos;
	TSize cursorSize;
	TPtrC stringBeforeCursor = aMatchableText.Left(aCharPos);
	TInt cursorWidth = 0;
	if (aCharPos < aMatchableText.Length())
		{
		TPtrC charAtCursor = aMatchableText.Mid(aCharPos,1);
        cursorWidth = Font(aCurrentItemIndex)->TextWidthInPixels(charAtCursor);
		}
	else
        cursorWidth = Font(aCurrentItemIndex)->MaxNormalCharWidthInPixels();
    cursorPos.iX = Font(aCurrentItemIndex)->TextWidthInPixels(stringBeforeCursor);
    if( Flags() & EDrawMarkSelection )
		cursorPos.iX += iMarkColumnWidth + iMarkGutter;
	cursorPos.iX += LafListBox::InnerGutter();
    cursorPos.iY = Font(aCurrentItemIndex)->AscentInPixels() + aItemCellYPos;
	cursorSize.iWidth = cursorWidth;
    cursorSize.iHeight = Font(aCurrentItemIndex)->HeightInPixels();
	TRect cursorRect(cursorPos, cursorSize);
	_AKNTRACE_FUNC_EXIT;
	return cursorRect;
	}

EXPORT_C TInt CTextListItemDrawer::MatcherCursorAscent( TInt aCurrentItemIndex ) const
	{
	// derived classes that deal with text and want to support incremental matching in
	// listboxes need to redefine this function

    // iFont replaced with Font(currentItem)
    return Font(aCurrentItemIndex)->AscentInPixels() - (VerticalInterItemGap()/2);
	}

EXPORT_C void CTextListItemDrawer::SetCellWidthInChars(TInt aNumOfCharsToDisplayInCell)
	{
	iNumOfCharsInCell = aNumOfCharsToDisplayInCell;
	}

EXPORT_C TSize CTextListItemDrawer::MinimumCellSize() const
	{
	//__ASSERT_DEBUG(0, Panic(EEikPanicOutOfRange));
	return TSize(0,0);
#ifdef THIS_IS_NOT_USED_IN_SERIES60
    TInt width;
    TInt height;
    
	if (iData && iData->FontBoundValues().iMaxNormalCharWidthInPixels)
        {
        //iFont->MaxNormalCharWidthInPixels() replaced with FontBoundValues().iMaxNormalCharWidthInPixels
        width = iNumOfCharsInCell * iData->FontBoundValues().iMaxNormalCharWidthInPixels;
        // iFont->HeightInPixels() replaced with FontBoundValues().iHeightInPixels
        height = iData->FontBoundValues().iHeightInPixels + VerticalInterItemGap();
        }
    else  // original code.
        {
		const CFont* font = ((iFont != NULL) ? iFont : CEikonEnv::Static()->NormalFont());
        width = iNumOfCharsInCell * font->MaxNormalCharWidthInPixels();
        height = font->HeightInPixels() + VerticalInterItemGap();
        }

	if (Flags()&CListItemDrawer::EDrawMarkSelection)
		{
		width += iMarkColumnWidth + iMarkGutter;
		}
	width+=LafListBox::InnerGutter();
	return TSize(width, height);
#endif
	}

/**
 * Draws the actual item contents for the item at index aItemIndex in the rectangle aActualItemRect.
 */
EXPORT_C void CTextListItemDrawer::DrawActualItem(TInt aItemIndex, const TRect& aActualItemRect,
        TBool aItemIsCurrent, TBool aViewIsEmphasized, TBool /*aViewIsDimmed*/, TBool aItemIsSelected) const
	{
	_AKNTRACE_FUNC_ENTER;
	if (Properties(aItemIndex).IsSelectionHidden()) { aItemIsSelected = EFalse; }

    if ( Flags() & EDisableHighlight
            || Flags() & ESingleClickDisabledHighlight )
        {
        aItemIsCurrent = EFalse;
        }

	DrawItemText(aItemIndex,aActualItemRect,aItemIsCurrent,aViewIsEmphasized,aItemIsSelected);
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C TInt CTextListItemDrawer::ItemWidthInPixels(TInt aItemIndex) const
	{
	return CListItemDrawer::ItemWidthInPixels(aItemIndex);
#ifdef THIS_IS_NOT_USED_IN_SERIES60
	TInt itemWidth = 0;
    if ( Flags() & EDrawMarkSelection )
		itemWidth += (iMarkColumnWidth + iMarkGutter);
	TPtrC des = iModel->ItemText(aItemIndex);
	if (des.Length())
        // iFont changed to Font(aItemIndex)
        itemWidth += Font(aItemIndex)->TextWidthInPixels(des);
	return itemWidth;
#endif
	}

EXPORT_C void CTextListItemDrawer::DoDrawItemText(const TDesC& aDes, const TRect& aItemTextRect,
		TBool aItemIsCurrent, TBool aViewIsEmphasized, TBool aItemIsSelected, TInt aItemIndex) const
	{
	//TRgb penColor=iTextColor; // original
    // New. If extended item drawer is used, pen color will be set setupGc function.
    //TRgb penColor;
	//TRgb brushColor=iBackColor;
	_AKNTRACE_FUNC_ENTER;
	iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
	iGc->SetBrushColor(iBackColor); 
    if (!iData)
		{
		iGc->SetPenColor(Properties(aItemIndex).Color());
		}

	if (Properties(aItemIndex).IsDimmed()) iGc->SetBrushColor(iDimmedBackColor);
    if (Flags()&EPaintedSelection)
		{
		if ( aItemIsSelected && aViewIsEmphasized)
			{
			iGc->SetPenColor(CEikonEnv::Static()->Color(EColorControlHighlightText));
			iGc->SetBrushColor(CEikonEnv::Static()->Color(EColorControlHighlightBackground));
			}
		}
	else
		{
		if (aItemIsCurrent && aViewIsEmphasized) // original code
			{
			iGc->SetPenColor(iHighlightedTextColor);
			iGc->SetBrushColor(iHighlightedBackColor); 
			}
		}
	if (Properties(aItemIndex).IsDimmed()) iGc->SetPenColor(iDimmedTextColor);

    const TInt extraVerticalSpace=aItemTextRect.Height()-Font(aItemIndex)->HeightInPixels();
    const TInt baseLineOffset=extraVerticalSpace/2 + Font(aItemIndex)->AscentInPixels();
	CGraphicsContext::TTextAlign align = iData ? iData->Alignment() : CGraphicsContext::ELeft;

	if ( iData && iData->IsSearchString() )
		{
		iData->DrawItem(*iGc,aItemTextRect,aDes,*Font(aItemIndex),baseLineOffset,align);
		}
	else
		{
		/*Call to the laf code which is responsible for drawing a text string in a rectangle*/
		LafTextListItemDrawer::DrawNormalText(aDes,*Font(aItemIndex),*iGc,aItemTextRect,baseLineOffset,align);
		}

	TInt attribute=0;
	if (!(Flags()&EPaintedSelection))
		{
		if (aItemIsCurrent && !aViewIsEmphasized)
			attribute|=CListItemDrawer::ECurrent;
		}
	else
		{
		if (aItemIsCurrent)
			attribute|=CListItemDrawer::ECurrent;
		else if ( !(Flags()&EDrawMarkSelection) && aItemIsSelected )
			attribute|=CListItemDrawer::ESelected;
		}
	if (attribute)
	CListItemDrawer::DrawFrame(*iGc,aItemTextRect,attribute);

	ResetGc();
	_AKNTRACE_FUNC_EXIT;
	}

EXPORT_C
void CTextListItemDrawer::DrawItemText( TInt aItemIndex,
                                        const TRect& aItemTextRect,
                                        TBool aItemIsCurrent,
                                        TBool aViewIsEmphasized,
                                        TBool aItemIsSelected ) const
    {
    _AKNTRACE_FUNC_ENTER;
    if (iData)
        {
        SetupGc(aItemIndex); // added
        }
    else
        {
        iGc->UseFont(iFont); // Original
        }
    
    TBufC<200> des = iModel->ItemText(aItemIndex);
    TPtrC target;
    target.Set(des);
    
    DoDrawItemText( target, aItemTextRect, aItemIsCurrent,
                    aViewIsEmphasized, aItemIsSelected, aItemIndex );

    iGc->DiscardFont();
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C inline const CFont* CTextListItemDrawer::Font(TInt aItemIndex) const
    {
    if (iData)
        return CListItemDrawer::Font(aItemIndex);
    else
		return iFont;
	}

EXPORT_C void CTextListItemDrawer::SetFont(const CFont* aFont)
	{
	iFont=aFont;
	}

EXPORT_C void CTextListItemDrawer::SetSearchStringL(const TDesC* aSearchString)
	{
	if (iData)
		iData->SetSearchStringL(aSearchString);
	}

EXPORT_C TAny* CTextListItemDrawer::Reserved_1()
	{
	return NULL;
	}














