idlehomescreen/xmluirendering/renderingplugins/xntextfactory/src/xntextadapter.cpp
/*
* Copyright (c) 2005-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: Implementation for wrapper for a label
*
*/
#include <e32base.h>
#include <coecntrl.h>
#include <barsread.h>
#include <gulcolor.h>
#include <utf.h>
#include <AknsUtils.h>
#include <AknPictographInterface.h> // for japanese variants.
#include <AknBidiTextUtils.h>
#include <AknUtils.h>
#include <AknLayoutFont.h>
#include "xnnodepluginif.h"
#include "xndompropertyvalue.h"
#include "xndomproperty.h"
#include "xndomlist.h"
#include "xnproperty.h"
#include "xncomponent.h"
#include "xnuienginepluginif.h"
#include "xncomponent.h"
#include "xncontroladapter.h"
#include "c_xnutils.h"
#include "xntype.h"
#include "xntextadapter.h"
#include "xncomponentnodeimpl.h"
#include "xnviewnodeimpl.h"
#include "xneditmode.h"
namespace XnText
{
const TUint8 KClip = 0x01;
const TUint8 KEllipse = 0x02;
const TUint8 KWrap = 0x04;
const TUint8 KOverflowVisible = 0x08;
const TUint8 KLtr = 0x10;
const TUint8 KConstructText = 0x20;
_LIT8( tooltip, "tooltip" );
_LIT8( clock, "clock" );
}
// -----------------------------------------------------------------------------
// IsBitSet
// Test whether bit is set in a flag
// -----------------------------------------------------------------------------
static TBool IsBitSet(TUint8 aBit,TUint8 aFlag)
{
return ( aFlag & aBit );
}
// -----------------------------------------------------------------------------
// SetLabelTextL
// Prepares text to label, wraps or clips if needed
// -----------------------------------------------------------------------------
static void SetLabelTextL( CEikLabel& aLabel, const TDesC& aSource, TInt aMaxLineWidth,
TInt aMaxLines, TUint8 aFlags, TBool aMeasureOnly = EFalse )
{
// By default, let the label do the logical to visual conversion
TBool conversion( ETrue );
if( IsBitSet( XnText::KOverflowVisible, aFlags ) || aSource == KNullDesC )
{
// no clipping or wrapping needed if,
// overflow is visible
// no text or no space,
// or text fits to given space
aLabel.SetTextL( aSource );
}
else
{
AknBidiTextUtils::TParagraphDirectionality dir( AknBidiTextUtils::EImplicit );
const CFont* font( aLabel.Font() );
HBufC* buffer( NULL );
if( IsBitSet( XnText::KEllipse, aFlags ) )
{
buffer = aSource.AllocLC();
TPtr ptr( buffer->Des() );
AknBidiTextUtils::ConvertToVisualAndClipL(
ptr, *font, aMaxLineWidth, aMaxLineWidth, dir );
// The text is already in visual form, no need for conversion
conversion = EFalse;
aLabel.SetTextL( *buffer );
CleanupStack::PopAndDestroy( buffer );
}
else if( IsBitSet( XnText::KWrap, aFlags ) )
{
if( aMaxLines > 0 )
{
CArrayFixFlat< TInt >* array = new ( ELeave ) CArrayFixFlat< TInt >( 8 );
CleanupStack::PushL( array );
for( TInt i = 0; i < aMaxLines; i++ )
{
array->AppendL( aMaxLineWidth );
}
buffer = HBufC::NewLC( aSource.Length() + aMaxLines *
( KAknBidiExtraSpacePerLine + 1 ) );
TPtr ptr( buffer->Des() );
AknBidiTextUtils::ConvertToVisualAndWrapToStringL(
aSource, *array, *font, ptr, ETrue, dir );
}
else
{
CArrayFixFlat< TPtrC >* array = new ( ELeave ) CArrayFixFlat< TPtrC >( 8 );
CleanupStack::PushL( array );
HBufC* temp = AknBidiTextUtils::ConvertToVisualAndWrapToArrayL(
aSource, aMaxLineWidth, *font, *array, dir );
CleanupStack::PushL( temp );
TInt lineCount( array->Count() );
TInt bufLen = temp->Length() + ( lineCount - 1 );
if ( bufLen > 0 )
{
buffer = HBufC::NewLC( bufLen );
TPtr ptr( buffer->Des() );
for( TInt i = 0; i < lineCount; i++ )
{
TPtrC line( array->At( i ) );
ptr.Append( line );
if( i + 1 < lineCount )
{
ptr.Append( '\n' );
}
}
CleanupStack::Pop();
CleanupStack::PopAndDestroy( temp );
CleanupStack::PushL( buffer );
}
else
{
CleanupStack::PopAndDestroy( temp );
}
}
// The text is already in visual form, no need for conversion
conversion = EFalse;
if ( buffer )
{
aLabel.SetTextL( *buffer );
CleanupStack::PopAndDestroy( buffer );
}
CleanupStack::PopAndDestroy(); // array
}
else
{
aLabel.SetTextL( aSource );
}
}
if( !aMeasureOnly )
{
// Text is truly set, set conversion and defer draw
aLabel.UseLogicalToVisualConversion( conversion );
}
}
// -----------------------------------------------------------------------------
// CopyBitmapData
// Copies a data from source bitmap to target bitmap.
// -----------------------------------------------------------------------------
//
static TInt CopyBitmapData(
CFbsBitmap& aTarget,
const CFbsBitmap& aSource,
TPoint aSourcePoint)
{
TSize targetSize(aTarget.SizeInPixels());
TSize sourceSize(aSource.SizeInPixels());
TInt lineLength(targetSize.iWidth);
TInt maxSourceLineLength(sourceSize.iWidth - aSourcePoint.iX);
if(lineLength > maxSourceLineLength)
{
lineLength = maxSourceLineLength;
}
TInt rowCount(targetSize.iHeight);
TInt maxSourceRowCount(sourceSize.iHeight - aSourcePoint.iY);
if(rowCount > maxSourceRowCount)
{
rowCount = maxSourceRowCount;
}
// Get bitmap display mode
TDisplayMode displayMode(aSource.DisplayMode());
// Create buffer for a scan line
HBufC8* scanLine = HBufC8::New(
aSource.ScanLineLength(lineLength, displayMode));
if(!scanLine)
{
return KErrNoMemory;
}
TPtr8 scanPtr(scanLine->Des());
// Copy all rows to destination bitmap
for(TInt row(0); row < rowCount; row++)
{
aSource.GetScanLine(scanPtr,
TPoint(aSourcePoint.iX, aSourcePoint.iY + row),
lineLength, displayMode);
aTarget.SetScanLine(scanPtr, row);
}
delete scanLine;
return KErrNone;
}
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CXnTextAdapter::NewL
// Symbian static 1st phase constructor
// -----------------------------------------------------------------------------
//
CXnTextAdapter* CXnTextAdapter::NewL(CXnControlAdapter* aParent, CXnNodePluginIf& aNode)
{
CXnTextAdapter* self = new( ELeave ) CXnTextAdapter( aParent, aNode );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop();
return self;
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::CXnTextAdapter
// C++ default constructor
// -----------------------------------------------------------------------------
//
CXnTextAdapter::CXnTextAdapter(CXnControlAdapter* aParent, CXnNodePluginIf& aNode)
: iParent( aParent ), iNode( aNode )
{
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::~CXnTextAdapter
// C++ destructor
// -----------------------------------------------------------------------------
//
CXnTextAdapter::~CXnTextAdapter()
{
delete iLabel;
delete iText;
if( iFont && iReleaseFont )
{
CWsScreenDevice* dev = iCoeEnv->ScreenDevice();
dev->ReleaseFont( iFont );
}
if( iPictographInterface )
{
delete iPictographInterface;
}
delete iBackgroundBitmap;
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::ConstructL()
{
iGc = &SystemGc();
iLabel = new ( ELeave ) CEikLabel;
iLabel->SetContainerWindowL( *iParent );
iLabel->SetTextL( KNullDesC );
CXnControlAdapter::ConstructL( iNode );
iPictographInterface = CAknPictographInterface::NewL( *iLabel, *this );
iLabel->EnablePictographsL( *iPictographInterface );
SetTextPropertiesL( iNode );
UpdateTextL( iNode.GetPCData() );
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::ConstructTextL
// Construct the text component according to properties.
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::ConstructTextL()
{
if( !iText )
{
// CEikLabel will panic in ::Draw if text is not set
SetLabelTextL( *iLabel, KNullDesC, 0, 0, 0 );
return;
}
if( !( iFlags & XnText::KConstructText ) )
{
return;
}
TRect rect( iNode.Rect() );
SetLineSpacingL( rect.Height() );
TInt flags( iFlags );
// Now we must restrict side into parent
flags = RestrictSizeL();
SetLabelTextL( *iLabel, *iText, iLabel->Rect().Width(), iMaxLines, flags );
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::SetTextPropertiesL
// Sets text properties, such as color, font, etc.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CXnTextAdapter::SetTextPropertiesL( CXnNodePluginIf& aNode )
{
// Store current state
const CFont* font( iFont );
TInt flags( iFlags );
TInt maxLines( iMaxLines );
if( iFont && iReleaseFont )
{
CWsScreenDevice* dev = iCoeEnv->ScreenDevice();
dev->ReleaseFont( iFont );
iFont = NULL;
}
// Find out the font and set it
CXnUtils::CreateFontL( aNode, iFont, iReleaseFont );
iLabel->SetFont( iFont );
// Turn off all graphic context effects
iLabel->SetUnderlining( EFalse );
iLabel->SetStrikethrough( EFalse );
//following data types are used due to we are handling text via CEikLabel instead of direct
//font color and effects manipulation via graphics context.
//We manipulate pen and brush colors indirectly via
//Label's OverrideColorL method applying EColorControlBackground and EColorLabelText parameters
//with corresponding RGB value.
TRgb textColor;
TRgb effectsColor;
TBool textColorSet( EFalse );
TBool effectsColorSet( EFalse );
TBool effectsDevColorSet( EFalse );
CXnProperty* colorProperty = aNode.GetPropertyL( XnPropertyNames::appearance::common::KColor );
if( colorProperty != NULL )
{
CXnDomProperty* domProperty = colorProperty->Property();
if( domProperty )
{
TInt error( KErrNotSupported );
CXnDomPropertyValue* value = static_cast< CXnDomPropertyValue* >
( domProperty->PropertyValueList().Item( 0 ) );
if( value->IsAutoIdent() )
{
MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
error = AknsUtils::GetCachedColor(skinInstance, textColor, KAknsIIDQsnTextColors,
EAknsCIQsnTextColorsCG6);
}
else if( value->PrimitiveValueType() == CXnDomPropertyValue::ERgbColor )
{
textColor = value->RgbColorValueL();
error = KErrNone;
}
else
{
HBufC* colorString = colorProperty->StringValueL();
CleanupStack::PushL( colorString );
CXnUtils::StripQuotes( colorString );
TInt index = 0;
TAknsItemID skinID;
TBool idResolved = CXnUtils::ResolveSkinItemIDL( colorString->Des(), skinID, index );
if( idResolved )
{
MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
error = AknsUtils::GetCachedColor( skinInstance, textColor, skinID, index );
}
else // use auto value if skin id is invalid.
{
MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
error = AknsUtils::GetCachedColor(skinInstance, textColor, KAknsIIDQsnTextColors,
EAknsCIQsnTextColorsCG6);
}
CleanupStack::PopAndDestroy( colorString );
}
if (error == KErrNone)
{
textColorSet = ETrue;
}
}
}
CXnProperty* effectsProperty = aNode.GetPropertyL(XnPropertyNames::appearance::common::KTextEffects);
if ( effectsProperty )
{
TInt error(KErrNotSupported);
effectsDevColorSet = ETrue; //some color needed, device color by default
CXnProperty* effectsColorProperty = aNode.GetPropertyL(XnPropertyNames::appearance::common::KEffectsColor);
if (effectsColorProperty)
{
CXnDomProperty* domProperty = effectsColorProperty->Property();
if( domProperty )
{
CXnDomPropertyValue* value = static_cast<CXnDomPropertyValue*>(domProperty->PropertyValueList().Item(0));
if (value->IsAutoIdent())
{
MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
error = AknsUtils::GetCachedColor(skinInstance, effectsColor, KAknsIIDQsnTextColors,
EAknsCIQsnTextColorsCG6);
}
else if (value->PrimitiveValueType() == CXnDomPropertyValue::ERgbColor)
{
effectsColor = value->RgbColorValueL();
error = KErrNone;
}
else
{
HBufC* colorString = effectsColorProperty->StringValueL();
CleanupStack::PushL( colorString );
CXnUtils::StripQuotes( colorString );
TInt index = 0;
TAknsItemID skinID;
TBool idResolved = CXnUtils::ResolveSkinItemIDL( colorString->Des(), skinID, index );
if( idResolved )
{
MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
error = AknsUtils::GetCachedColor( skinInstance, effectsColor, skinID, index );
}
else // use auto value if skin id is invalid.
{
MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
error = AknsUtils::GetCachedColor(skinInstance, effectsColor, KAknsIIDQsnTextColors,
EAknsCIQsnTextColorsCG6);
}
CleanupStack::PopAndDestroy( colorString );
}
if ( error == KErrNone )
{
effectsColorSet = ETrue; //theme color found
effectsDevColorSet = EFalse;//device color not needed
}
}
}
}
if ( textColorSet )
{
if ( effectsColorSet )
{//theme font color and theme effects color
iLabel->OverrideColorL(EColorControlBackground, textColor);
iLabel->OverrideColorL(EColorLabelText, effectsColor);
}
else if ( effectsDevColorSet )
{//theme font color and device effects color
iLabel->OverrideColorL(EColorControlBackground, textColor);
}
else
{//theme font color, but no effects defined
iLabel->OverrideColorL(EColorLabelText, textColor);
}
}
else if ( effectsColorSet )
{//device font color and theme effects color
iLabel->OverrideColorL(EColorLabelText, effectsColor);
}//else device font color and device effects color (default)
CXnProperty* textDecorationProp = aNode.GetPropertyL( XnPropertyNames::appearance::common::KTextDecoration );
if( textDecorationProp )
{
CXnDomList& propertyValueList = textDecorationProp->Property()->PropertyValueList();
TInt valueCount = propertyValueList.Length();
for( TInt i = 0; i < valueCount; ++i )
{
CXnDomPropertyValue* value = static_cast< CXnDomPropertyValue* >( propertyValueList.Item( i ) );
if( value->StringValueL() == XnPropertyNames::appearance::common::textdecoration::KUnderline )
{
iLabel->SetUnderlining( ETrue );
}
if( value->StringValueL() == XnPropertyNames::appearance::common::textdecoration::KLinethrough )
{
iLabel->SetStrikethrough( ETrue );
}
}
}
iFlags = 0;
iFlags |= XnText::KEllipse; //default
iFlags |= XnText::KLtr;
iMaxLines = 0;
TGulAlignmentValue alignment = CXnUtils::TextAlignment( aNode );
TInt labelAlignment( ELayoutAlignLeft ); // all are vertically top aligned by default (avkon)
switch( alignment )
{
case EHCenterVCenter:
labelAlignment = ELayoutAlignCenter;
break;
case EHRightVCenter:
labelAlignment = ELayoutAlignRight;
break;
default:
break;
}
iLabel->SetLabelAlignment( labelAlignment ); // avkon extension needs this, it modifys horizontal alignment
iLabel->SetAlignment( alignment ); // call to have vertical alignment
CXnProperty* direction = iNode.GetPropertyL( XnPropertyNames::style::common::KDirection );
const TDesC8* directionValue = &XnPropertyNames::style::common::direction::KLTR;
if( direction )
{
directionValue = &direction->StringValue();
}
if( *directionValue == XnPropertyNames::style::common::direction::KRTL )
{
iLabel->SetLabelAlignment( ELayoutAlignBidi );
iFlags &= ~XnText::KLtr;
}
CXnProperty* overflowProp = aNode.GetPropertyL( XnPropertyNames::appearance::common::KTextOverflowMode );
if( overflowProp )
{
CXnDomList& propertyValueList = overflowProp->Property()->PropertyValueList();
TInt valueCount = propertyValueList.Length();
for( TInt i = 0; i < valueCount; ++i )
{
CXnDomPropertyValue* value = static_cast< CXnDomPropertyValue* >( propertyValueList.Item( i ) );
if( value->StringValueL() == XnPropertyNames::appearance::common::textoverflow::KClipMode )
{
iFlags |= XnText::KClip;
iFlags &= ~XnText::KWrap;
iFlags &= ~XnText::KEllipse;
}
else if( value->StringValueL() == XnPropertyNames::appearance::common::textoverflow::KWrapMode )
{
iFlags |= XnText::KWrap;
iFlags &= ~XnText::KClip;
iFlags &= ~XnText::KEllipse;
}
}
//Get max lines amount for wrap
if( iFlags & XnText::KWrap )
{
CXnProperty* maxlinesProp = aNode.GetPropertyL( XnPropertyNames::appearance::common::textoverflow::KMaxLineAmount );
if( maxlinesProp )
{
iMaxLines = static_cast< TInt >( maxlinesProp->FloatValueL() );
}
}
}
CXnProperty* overflowProperty = iNode.GetPropertyL( XnPropertyNames::style::common::KOverflow );
if( overflowProperty )
{
const TDesC8& overflowValue = overflowProperty->StringValue();
if( overflowValue == XnPropertyNames::style::common::visibility::KVisible )
{
iFlags |= XnText::KOverflowVisible;
}
}
if( flags & XnText::KConstructText )
{
iFlags |= XnText::KConstructText;
}
if( font != iFont || flags != iFlags || maxLines != iMaxLines )
{
return ETrue;
}
return EFalse;
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::SetTextL
// Sets the new content to the underlying CEikLabel
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::SetTextL( const TDesC& aText )
{
UpdateTextL( &aText );
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::Text
// Returns the text contained in the underlying CEikLabel
// -----------------------------------------------------------------------------
//
const TDesC* CXnTextAdapter::Text() const
{
if( iFlags & XnText::KConstructText )
{
return iText;
}
else
{
return iLabel->Text();
}
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::CountComponentControls
// Returns the number of component controls.
// -----------------------------------------------------------------------------
//
TInt CXnTextAdapter::CountComponentControls() const
{
return 1;
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::ComponentControl
// Returns the component control of the given index
// -----------------------------------------------------------------------------
//
CCoeControl* CXnTextAdapter::ComponentControl(TInt aIndex) const
{
if( aIndex == 0 )
{
return iLabel;
}
return NULL;
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::DoHandlePropertyChangeL
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::DoHandlePropertyChangeL(CXnProperty* aProperty)
{
if( aProperty )
{
const TDesC8& name( aProperty->Property()->Name() );
if( name == XnPropertyNames::style::common::KDisplay ||
name == XnPropertyNames::style::common::KVisibility ||
name == XnPropertyNames::style::common::KWidth ||
name == XnPropertyNames::style::common::KHeight )
{
return;
}
if( name == XnPropertyNames::common::KPCData )
{
UpdateTextL( iNode.GetPCData() );
}
}
if( SetTextPropertiesL( iNode ) )
{
iFlags |= XnText::KConstructText;
}
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::HandleResourceChange
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::HandleScreenDeviceChangedL()
{
if( SetTextPropertiesL( iNode ) )
{
iFlags |= XnText::KConstructText;
}
CXnControlAdapter::HandleScreenDeviceChangedL();
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::HandlePointerEventL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::HandlePointerEventL( const TPointerEvent& aPointerEvent )
{
if( AknLayoutUtils::PenEnabled() )
{
CXnControlAdapter::HandlePointerEventL( aPointerEvent );
}
}
// ---------------------------------------------------------
// CXnTextAdapter::SizeChanged()
// Called by framework when the view size is changed
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CXnTextAdapter::SizeChanged()
{
TRAP_IGNORE( SizeChangedL() );
}
// ---------------------------------------------------------
// CXnTextAdapter::SizeChangedL()
// ---------------------------------------------------------
//
void CXnTextAdapter::SizeChangedL()
{
if( SetTextPropertiesL( iNode ) )
{
iFlags |= XnText::KConstructText;
}
TRect rect( iNode.Rect() );
TRect labelRect( iLabel->Rect() );
iLabel->SetRect( rect );
if( iText )
{
TInt textWidth( iLabel->Font()->TextWidthInPixels( *iText ) );
TInt rectWidth( rect.Width() );
if( iFlags & XnText::KOverflowVisible )
{
TBool isTooltip( iNode.ParentL()->Type()->Type() == XnText::tooltip );
// Tooltip can grow and shrink, others just grow
if( isTooltip || textWidth > rectWidth )
{
rect = Rect();
TInt dx( textWidth - rectWidth );
if( dx != 0 )
{
rect.Resize( dx, 0 );
SetSizeWithoutNotification( rect.Size() );
// Update
iLabel->SetRect( rect );
}
}
}
}
if( labelRect != iLabel->Rect() )
{
iFlags |= XnText::KConstructText;
}
}
// ---------------------------------------------------------
// CXnTextAdapter::SkinChanged()
// Called by framework when the skin is changed
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CXnTextAdapter::SkinChanged()
{
TRAP_IGNORE
(
if( SetTextPropertiesL( iNode ) )
{
iFlags |= XnText::KConstructText;
}
);
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::Draw
// Draws the text component
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::Draw(const TRect& aRect) const
{
CXnTextAdapter* adapter = const_cast< CXnTextAdapter* >( this );
if( iFlags & XnText::KConstructText )
{
TRAPD( err, adapter->ConstructTextL() );
adapter->iFlags &= ~XnText::KConstructText;
if( err )
{
return;
}
}
CXnControlAdapter::Draw( aRect );
if( iPictographInterface )
{
TRAP_IGNORE( UpdateBackgroundL() );
iGc->BitBlt( iNode.Rect().iTl, iBackgroundBitmap );
}
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::DrawPictographArea
// Draws the text component
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::DrawPictographArea()
{
DrawNow();
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::UpdateBackgroundL
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::UpdateBackgroundL() const
{
CGraphicsDevice* gdevice = iGc->Device();
TDisplayMode displayMode = gdevice->DisplayMode();
// create "screenshot" from the background appearance
if( iBackgroundBitmap )
{
delete iBackgroundBitmap;
iBackgroundBitmap = NULL;
}
iBackgroundBitmap = new (ELeave) CFbsBitmap();
iBackgroundBitmap->Create( iNode.Rect().Size(), displayMode );
CFbsBitmap* tmpBitmap = new (ELeave) CFbsBitmap;
CleanupStack::PushL( tmpBitmap );
CWsScreenDevice* scrDevice = static_cast<CWsScreenDevice*>( iGc->Device() );
TSize tmpSize = scrDevice->SizeInPixels();
tmpBitmap->Create( tmpSize, displayMode );
CFbsBitmapDevice* tmpDevice = CFbsBitmapDevice::NewL( tmpBitmap );
CleanupStack::PushL( tmpDevice );
CBitmapContext* bc( NULL );
tmpDevice->CreateBitmapContext( bc );
CleanupStack::PushL( bc );
DrawBackground( iNode.Rect(), reinterpret_cast<CWindowGc&>( *bc ) );
CopyBitmapData( *iBackgroundBitmap, *tmpBitmap, iNode.Rect().iTl );
CleanupStack::PopAndDestroy( 3 );
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::DrawBackground
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::DrawBackground(const TRect& aRect, CWindowGc& aGc) const
{
RPointerArray<CXnControlAdapter> adapters;
for( CXnNodePluginIf* node = &iNode; node; )
{
TRAP_IGNORE(
CXnControlAdapter* adapter( node->Control() );
if ( adapter )
{
adapters.AppendL( adapter );
}
node = node->ParentL()
);
}
for( TInt i = adapters.Count() - 1; i >= 0; --i )
{
adapters[i]->Draw( aRect, aGc );
}
adapters.Reset();
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::MeasureAdaptiveContentL
// -----------------------------------------------------------------------------
//
TSize CXnTextAdapter::MeasureAdaptiveContentL( const TSize& aAvailableSize )
{
TSize size;
if( ( aAvailableSize.iWidth > 0 ) && ( aAvailableSize.iHeight > 0 ) )
{
size = MeasureTextL( aAvailableSize );
}
return size;
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::RestrictSizeL
// -----------------------------------------------------------------------------
//
TInt CXnTextAdapter::RestrictSizeL()
{
CXnNodePluginIf* parent( iNode.ParentL() );
if( !parent )
{
// No parent where to restrict own size
return iFlags;
}
TRect parentRect( parent->Rect() );
if( parentRect.IsEmpty() )
{
return iFlags;
}
TRect rect( Rect() );
TInt dx( 0 );
TInt dy( 0 );
// Restrict own size inside parent rect to prevent flowing outside parent's rect
if( rect.iBr.iX > parentRect.iBr.iX )
{
dx = rect.iBr.iX - parentRect.iBr.iX;
}
if( rect.iBr.iY > parentRect.iBr.iY )
{
dy = rect.iBr.iY - parentRect.iBr.iY;
}
if( dx == 0 && dy == 0 )
{
// No need to change sizes
return iFlags;
}
TInt flags( iFlags );
if( parent->Type()->Type() == XnText::tooltip )
{
// Remove temporarily to allow tooltip truncation
flags &= ~XnText::KOverflowVisible;
}
// Clip text again, parent size restriction may result in re-clipping
if( !IsBitSet( XnText::KOverflowVisible, flags ) )
{
TSize size( rect.Size() );
size.iWidth -= dx;
size.iHeight -= dy;
// Update own size ...
SetSizeWithoutNotification( size );
// ... and label
rect = iLabel->Rect();
rect.Resize( -dx, -dy );
iLabel->SetRect( rect );
}
return flags;
}
// -----------------------------------------------------------------------------
// CXnTextAdapter::SetLineSpacingL
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::SetLineSpacingL( TInt aReference )
{
// Set linespacing, one pixel is the default
TInt lineSpace( 1 );
CXnProperty* lineSpaceProp(
iNode.GetPropertyL( XnPropertyNames::appearance::common::KFontLineSpace ) );
if( lineSpaceProp )
{
lineSpace = iNode.UiEngineL()->VerticalPixelValueL( lineSpaceProp, aReference );
}
if( lineSpace < 1 )
{
// Must be at least 1
lineSpace = 1;
}
const CAknLayoutFont* layoutFont( CAknLayoutFont::AsCAknLayoutFontOrNull( iFont ) );
if( layoutFont )
{
TInt textPaneHeight = layoutFont->TextPaneHeight();
lineSpace += ( textPaneHeight - iFont->HeightInPixels() );
}
/* end of CEikLabel fix */
iLabel->SetPixelGapBetweenLines( lineSpace );
}
// -----------------------------------------------------------------------------
// MeasureTextL
// Measures the text dimensions fitted to available size
// -----------------------------------------------------------------------------
//
TSize CXnTextAdapter::MeasureTextL( const TSize& aAvailableSize )
{
TSize size;
if( !iText || *iText == KNullDesC )
{
return size;
}
// Save the current text before measure
HBufC* original( iLabel->Text()->AllocLC() );
SetLineSpacingL( 0 );
SetLabelTextL( *iLabel, *iText, aAvailableSize.iWidth, iMaxLines, iFlags, ETrue );
TPtrC text( *iLabel->Text() );
// help CEikLabel to calculate its content size more precisely
iLabel->iMargin.iBottom = iLabel->Font()->DescentInPixels();
// Get the size needed for the text
size = iLabel->CalcMinimumSize( text );
// Restore original text
iLabel->SetTextL( *original );
CleanupStack::PopAndDestroy( original );
return size;
}
// -----------------------------------------------------------------------------
// UpdateTextL
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::UpdateTextL( const TDesC8& aText )
{
HBufC* text( CnvUtfConverter::ConvertToUnicodeFromUtf8L( aText ) );
CleanupStack::PushL( text );
UpdateTextL( text );
CleanupStack::PopAndDestroy( text );
}
// -----------------------------------------------------------------------------
// UpdateTextL
// -----------------------------------------------------------------------------
//
void CXnTextAdapter::UpdateTextL( const TDesC* aText )
{
if( aText )
{
if( iText && *iText == *aText )
{
// New text is same as current
return;
}
if( iText && iText->Des().MaxLength() >= aText->Length() )
{
// New text fits to earlier allocated space
*iText = *aText;
}
else
{
// Need to reserve space for new text
delete iText;
iText = NULL;
iText = aText->AllocL();
}
TPtr ptr( iText->Des() );
CXnUtils::CollapseWhiteSpace( iNode, ptr );
iFlags |= XnText::KConstructText;
iNode.SetDirtyL();
const TDesC8& parentType( iNode.ParentL()->Type()->Type() );
if( parentType == XnText::tooltip )
{
// Force tooltip text size to be recalculted by layout algorithm
SetSizeWithoutNotification( TSize() );
}
else if( parentType == XnText::clock )
{
iNode.ParentL()->SetDirtyL();
}
}
}
// End of file