diff -r 000000000000 -r 2f259fa3e83a uifw/EikStd/coctlsrc/EIKLABEL.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/EikStd/coctlsrc/EIKLABEL.CPP Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,841 @@ +/* +* Copyright (c) 1997-1999 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 +#include +#include +#include +#include +#include +#include "laflabel.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include + +const TInt KTextEmphasisMask = 0x30; +const TInt KTextBufferReserveLength = 0x40; + + +/* This class needs to be in .cpp file so that we + do not accidentally make it derivable; that would + destroy all the binary compability advantages this + class has.. + */ +NONSHARABLE_CLASS(CEikLabelExtension) : public CBase + { +public: // enums + enum { + ECropText, + EUseDynamicBidiTextAlignment, + EUseBrushStyle + }; +public: + static CEikLabelExtension* NewL(); + ~CEikLabelExtension(); + void SetTextLengthL(TInt aLength); + +private: + CEikLabelExtension(); + void ConstructL(); +public: //data + HBufC* iLabelLine; + TBitFlags iFlags; + CWindowGc::TBrushStyle iBrushStyle; + CAknPictographInterface* iPictographInterface; // not owned + }; + +CEikLabelExtension* CEikLabelExtension::NewL() + { + CEikLabelExtension* self = new(ELeave) CEikLabelExtension; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CEikLabelExtension::CEikLabelExtension() + { + iFlags.ClearAll(); + } + +CEikLabelExtension::~CEikLabelExtension() + { + delete iLabelLine; + } + +void CEikLabelExtension::ConstructL() + { + iLabelLine = HBufC::NewL(0); + } + +void CEikLabelExtension::SetTextLengthL(TInt aLength) + { + aLength += TBidiLogicalToVisual::KMinCharAvailable; + if (aLength <= iLabelLine->Des().MaxLength()) + return; + + HBufC* tempBuf = HBufC::NewL(aLength); + delete iLabelLine; + iLabelLine = tempBuf; + } + +/** + * Gets the list of logical colors employed in the drawing of the control, + * paired with an explanation of how they are used. Appends the list to aColorUseList. + * + * @since ER5U + */ +EXPORT_C void CEikLabel::GetColorUseListL(CArrayFix& aColorUseList) const + { + CCoeControl::GetColorUseListL(aColorUseList); + + TInt commonAttributes = TCoeColorUse::ESurrounds|TCoeColorUse::ENormal|TCoeColorUse::ENeutral; + TCoeColorUse colorUse; + + colorUse.SetLogicalColor(EColorLabelText); + colorUse.SetUse(TCoeColorUse::EFore|TCoeColorUse::EActive|commonAttributes); + aColorUseList.AppendL(colorUse); + + colorUse.SetLogicalColor(EColorControlBackground); + colorUse.SetUse(TCoeColorUse::EBack|TCoeColorUse::EActive|commonAttributes); + aColorUseList.AppendL(colorUse); + + colorUse.SetLogicalColor(EColorLabelDimmedText); + colorUse.SetUse(TCoeColorUse::EFore|TCoeColorUse::EDimmed|commonAttributes); + aColorUseList.AppendL(colorUse); + + TInt highlightAttributes = TCoeColorUse::EHighlights|TCoeColorUse::ENormal|TCoeColorUse::ENeutral; + + colorUse.SetLogicalColor(EColorLabelTextEmphasis); + colorUse.SetUse(TCoeColorUse::EFore|TCoeColorUse::EActive|highlightAttributes); + aColorUseList.AppendL(colorUse); + + colorUse.SetLogicalColor(EColorLabelHighlightFullEmphasis); + colorUse.SetUse(TCoeColorUse::EBack|TCoeColorUse::EActive|highlightAttributes); + aColorUseList.AppendL(colorUse); + + colorUse.SetLogicalColor(EColorLabelHighlightPartialEmphasis); + colorUse.SetUse(TCoeColorUse::EBack|TCoeColorUse::EDimmed|highlightAttributes); + aColorUseList.AppendL(colorUse); + } + +/** + * Handles a change to the control's resources of type aType + * which are shared across the environment, e.g. colors or fonts. + * + * @since ER5U + */ +EXPORT_C void CEikLabel::HandleResourceChange(TInt aType) + { + CCoeControl::HandleResourceChange(aType); + } + +EXPORT_C CEikLabel::~CEikLabel() + { + delete iText; + delete iExtension; + } + +EXPORT_C CEikLabel::CEikLabel() : + iLabFlags( EUseLogicalToVisualConversion ), + iGapBetweenLines( LafLabel::DefaultGapBetweenLines() ) + { + __DECLARE_NAME(_S("CEikLabel")); + iFont=iCoeEnv->NormalFont(); + } + +EXPORT_C void CEikLabel::SetLabelAlignment(TInt aAlignment) + { + if (CheckAndCreateExtension()) + iExtension->iFlags.Assign(CEikLabelExtension::EUseDynamicBidiTextAlignment, (aAlignment == ELayoutAlignBidi)); + + switch(aAlignment) + { + case ELayoutAlignBidi: // alignment handled above in extension above + break; + default: + SetAlignment(AknLayoutUtils::GulAlignFromId(aAlignment)); + break; + } + } + +EXPORT_C void CEikLabel::SetBrushStyle(CWindowGc::TBrushStyle aBrushStyle) + { + if (CheckAndCreateExtension()) + { + iExtension->iBrushStyle = aBrushStyle; + iExtension->iFlags.Set(CEikLabelExtension::EUseBrushStyle); + } + } + +EXPORT_C void CEikLabel::SetBrushStyleFromContext() + { + if (CheckAndCreateExtension()) // can't be sure creation above passed + { + iExtension->iFlags.Clear(CEikLabelExtension::EUseBrushStyle); + } + } + +EXPORT_C void CEikLabel::ConstructFromResourceL(TResourceReader& aReader) + { + TInt flags=aReader.ReadInt16(); + SetUnderlining(flags&EikLabelUnderline); + SetStrikethrough(flags&EikLabelStrikeThrough); + iAlignment.SetHAlignment((TGulHAlignment)aReader.ReadInt16()); + iAlignment.SetVAlignment((TGulVAlignment)aReader.ReadInt16()); + TInt standardFont=aReader.ReadInt16(); + switch (standardFont) + { + case EEikLabelFontLegend: + iFont=iEikonEnv->LegendFont(); + break; + case EEikLabelFontAnnotation: + iFont=iEikonEnv->AnnotationFont(); + break; + default: + break; + } + TInt length=aReader.ReadInt16(); + if (length) + SetBufferReserveLengthL(length); + SetTextL(aReader.ReadTPtrC()); + } + +EXPORT_C void CEikLabel::SetTextL(const TDesC& aText) + { + __ASSERT_DEBUG(&aText,Panic(EEikPanicLabelNullText)); + + if (iLabFlags&KTextBufferReserveLength || + (iText && iText->Des().MaxLength() >= aText.Length())) + { + *iText=aText; // will panic if not long enough + } + else + { + User::LeaveIfError( AknBidiTextUtils::PrepareRunInfoArray( aText ) ); + + HBufC* newText=aText.AllocL(); + delete(iText); // after the AllocL succeeds + iText=newText; + + if ( !iExtension ) + { + iExtension = CEikLabelExtension::NewL(); + } + iExtension->SetTextLengthL(iText->Length()); + } + if (iExtension) + iExtension->iFlags.Clear(CEikLabelExtension::ECropText); // reset ECropText + iNumberOfLines=1; + TPtrC ptr=(*iText); + FOREVER + { + const TInt offset=ptr.Locate('\n'); + if (offset<0 || offset==ptr.Length()-1) + break; + iNumberOfLines++; + ptr.Set(ptr.Mid(offset+1)); + } + return ; + } + +EXPORT_C void CEikLabel::CropText() + { + if ( iExtension ) // if no extension do nothing as SetTextL has not yet been called + iExtension->iFlags.Set(CEikLabelExtension::ECropText); + } + +TInt CEikLabel::HeightInPixels() const + { + return(iMargin.iTop+iMargin.iBottom + iGapBetweenLines*(iNumberOfLines-1) + iNumberOfLines*iFont->HeightInPixels()); + } + +TInt CEikLabel::WidthInPixels(TPtrC& aText) const + { + TInt maxLineWidth=0; + + FOREVER + { + const TInt offset=aText.Locate('\n'); + TPtrC left=aText; + if (offset>=0) + left.Set(aText.Left(offset)); + + CFont::TMeasureTextInput input; + if ( !(iLabFlags & EUseLogicalToVisualConversion) ) + { + input.iFlags = CFont::TMeasureTextInput::EFVisualOrder; + } + TInt thisWidth = iFont->MeasureText( left, &input ); + + if (thisWidth>maxLineWidth) + maxLineWidth=thisWidth; + if (offset<0 || offset==aText.Length()-1) + break; + aText.Set(aText.Mid(offset+1)); + } + return(iMargin.iLeft + iMargin.iRight + maxLineWidth); + } + +TInt CEikLabel::HeightInPixels(const TDesC& aText) const + { + // Calculate amount of lines in aText + TInt numberOfLines = 1; + TPtrC ptr=aText; + FOREVER + { + const TInt offset=ptr.Locate('\n'); + if (offset<0 || offset==ptr.Length()-1) + break; + numberOfLines++; + ptr.Set(ptr.Mid(offset+1)); + } + + // Calculate height. + return(iMargin.iTop+iMargin.iBottom + iGapBetweenLines*(numberOfLines-1) + numberOfLines*iFont->HeightInPixels()); + } + +EXPORT_C void CEikLabel::Draw( const TRect& /*aRect*/ ) const + { + CWindowGc& gc = SystemGc(); + DrawToContext( gc, NULL ); + gc.SetOpaque( EFalse ); // transparency back on + } + + +void CEikLabel::DrawToContext( CBitmapContext& aContext, + const TRgb* aOverrideColor ) const + { + __ASSERT_ALWAYS(iText,Panic(EEikPanicLabelNullText)); + TInt textTooLong = KErrNone; + if (iExtension->iLabelLine->Des().MaxLength() < iText->Length() + TBidiLogicalToVisual::KMinCharAvailable) + { + TRAP(textTooLong, iExtension->SetTextLengthL(iText->Length())); + } // textTooLong condition is handled later in this function, tries to recover as much as possible + + TBool outlineEffectOn = EFalse; + const CAknLayoutFont* layoutFont = CAknLayoutFont::AsCAknLayoutFontOrNull( iFont ); + if (layoutFont) + { + outlineEffectOn = layoutFont->FontSpecification().IsOutlineEffectOn(); + } + + CBitmapContext& gc = aContext; + if (IsStrikethrough()) + { + gc.SetStrikethroughStyle(EStrikethroughOn); + } + else + { + gc.SetStrikethroughStyle(EStrikethroughOff); + } + + if (IsUnderlined()) + { + gc.SetUnderlineStyle(EUnderlineOn); + } + else + { + gc.SetUnderlineStyle(EUnderlineOff); + } + + if ( aOverrideColor ) + { + gc.SetPenColor(*aOverrideColor); + gc.SetBrushColor(*aOverrideColor); + } + else if ((iLabFlags&KTextEmphasisMask) != ENoEmphasis) + { + SetupGcForEmphasis(gc); + } + else + { + TRgb penColor; + TRgb brushColor; + if (IsDimmed()) + { + penColor = iEikonEnv->ControlColor(EColorLabelDimmedText,*this); + brushColor = iEikonEnv->ControlColor(EColorControlDimmedBackground,*this); + } + else + { + penColor = iEikonEnv->ControlColor(EColorLabelText,*this); + brushColor = iEikonEnv->ControlColor(EColorControlBackground,*this); + } + if(outlineEffectOn) + { + ConvertColorsForOutlineEffect(penColor, brushColor); + } + gc.SetPenColor(penColor); + gc.SetBrushColor(brushColor); + } + + + gc.UseFont(iFont); + + if (iExtension->iFlags.IsSet(CEikLabelExtension::EUseBrushStyle)) + { + gc.SetBrushStyle(iExtension->iBrushStyle); + } + + const TRect rect = Rect(); + + const TInt deltaHeight=rect.Height()-HeightInPixels(); + TInt preHeight=iMargin.iTop; // used on first line + TInt postHeight=iMargin.iBottom; // used on last line + if (deltaHeight>0) + { + switch(iAlignment.VAlignment()) + { + case EVTop: + postHeight+=deltaHeight; + break; + case EVBottom: + preHeight+=deltaHeight; + break; + case EVCenter: + TInt postInc=deltaHeight/2; // give odd pixel to pre-Height + preHeight+=deltaHeight-postInc; + postHeight+=postInc; + } + } + TInt lineNo=0; + + TPtrC ptr=(*iText); + TRect box=rect; + TBool clippedAtBottom=EFalse; + TInt textPaneTopToBaseline(0); + TInt textPaneHeight(0); + + if ( layoutFont ) + { + textPaneTopToBaseline = layoutFont->TextPaneTopToBaseline(); + textPaneHeight = layoutFont->TextPaneHeight(); + } + else + { + textPaneTopToBaseline = iFont->AscentInPixels(); + textPaneHeight = iFont->HeightInPixels(); + } + + // iGapBetweenLines is defined as baseline separation - CFont::HeightInPixels + // Since we are using the better metrics above, we have to actually use something which is + // derived from iGapBetweenLines, but is e.g. reduced if textpaneheight > heightInPixels + TInt gapBetweenTextPanes( iGapBetweenLines - (textPaneHeight - iFont->HeightInPixels()) ); + + FOREVER + { + TInt ascent=textPaneTopToBaseline+preHeight; + TInt lineHeight=textPaneHeight+preHeight; + if (++lineNo==iNumberOfLines) + { + lineHeight+=postHeight; + } + + TInt off=ptr.Locate('\n'); + TPtrC left=ptr; + if (off>=0) + { + left.Set(ptr.Left(off)); + } + + box.iBr.iY=box.iTl.iY+lineHeight; + if (box.iBr.iY>rect.iBr.iY) + { + box.iBr.iY=rect.iBr.iY; + clippedAtBottom=ETrue; + } + + CGraphicsContext::TTextAlign align=iAlignment.TextAlign(); + TInt margin = iMargin.iLeft; + + TBidiText::TDirectionality labelDirectionality = TBidiText::TextDirectionality(*iText); + if (iExtension->iFlags.IsSet(CEikLabelExtension::EUseDynamicBidiTextAlignment)) + { + switch(labelDirectionality) + { + case TBidiText::ELeftToRight: + align = CGraphicsContext::ELeft; + break; + case TBidiText::ERightToLeft: + align = CGraphicsContext::ERight; + break; + default: + break; // do nothing + } + } + + if (align==CGraphicsContext::ERight) + { + margin = iMargin.iRight; + } + else if (align==CGraphicsContext::ECenter) + { + margin -= iMargin.iRight; + } + + TRect adjustedBox( box ) ; // create a new box to accommodate underline if present (without affecting layout) + if ( IsUnderlined() ) + { + TAknTextDecorationMetrics decoration(iFont); + TInt underlineWidth = decoration.UnderlineHeight(); + TInt underlineSpace = decoration.BaselineToUnderlineOffset(); + + if ( ( textPaneTopToBaseline + underlineSpace ) > textPaneHeight ) + { + adjustedBox.iBr.iY += ( textPaneTopToBaseline + underlineSpace - textPaneHeight ) ; + } + } + + TPtr text = iExtension->iLabelLine->Des(); + TInt textMaxLength = text.MaxLength(); + TBool dontDoComplicatedDraw = EFalse; + + TInt usableLength = 0; + if (textTooLong == KErrNone || textMaxLength >= left.Length() + TBidiLogicalToVisual::KMinCharAvailable) + { + usableLength = left.Length(); // no problem with memory + } + else + { // problem with lack of memory so find a usable length. + if (labelDirectionality == TBidiText::ELeftToRight || !(iLabFlags & EUseLogicalToVisualConversion)) + { // most likely western text so just display logically (no truncation) + dontDoComplicatedDraw = ETrue; + } + else + { // most likely NOT western text so display as much visually as possible + if (textMaxLength > TBidiLogicalToVisual::KMinCharAvailable) + { + usableLength = textMaxLength - TBidiLogicalToVisual::KMinCharAvailable; + } + else // there is no buffer so give up and draw logically + { + dontDoComplicatedDraw = ETrue; + } + } + } + + if (dontDoComplicatedDraw) + { + gc.DrawText( left, adjustedBox, ascent, align, margin ); + if ( iExtension->iPictographInterface ) + { + iExtension->iPictographInterface->Interface()->DrawPictographsInText( + gc, *iFont, left, adjustedBox, ascent, align, margin ); + } + } + else + { // we have some buffer space to try and draw text correctly + TPtrC usableText=left.Left(usableLength); + TInt adjustedBoxWidth = adjustedBox.Size().iWidth; + + if (iLabFlags & EUseLogicalToVisualConversion) + { + if (iExtension->iFlags.IsSet(CEikLabelExtension::ECropText)) + { + AknBidiTextUtils::ConvertToVisualAndClip(usableText, text, *iFont, adjustedBoxWidth, adjustedBoxWidth); + } + else + { + const TUint KEmptyChar = TUint(0xFFFF); + AknBidiTextUtils::ConvertToVisualAndClip(usableText, text, *iFont, adjustedBoxWidth, adjustedBoxWidth, AknBidiTextUtils::EImplicit, KEmptyChar ); + } + } + else + { + text = usableText; // copy + } + gc.DrawText( text, adjustedBox, ascent, align, margin ); + if ( iExtension->iPictographInterface ) + { + iExtension->iPictographInterface->Interface()->DrawPictographsInText( + gc, *iFont, text, adjustedBox, ascent, align, margin ); + } + } + + + if (off<0 || off==ptr.Length()-1 || clippedAtBottom) + break; + + ptr.Set(ptr.Mid(off+1)); + box.iTl.iY=box.iBr.iY; + + preHeight=gapBetweenTextPanes; + } + + gc.DiscardFont(); + } + +EXPORT_C void CEikLabel::SetBufferReserveLengthL(TInt aLength) + { + if (iText) + iText=iText->ReAllocL(aLength); + else + iText=HBufC::NewL(aLength); + iLabFlags|=KTextBufferReserveLength; + iReserveLength=aLength; + if ( !iExtension ) + { + iExtension = CEikLabelExtension::NewL(); + } + iExtension->SetTextLengthL(iText->Length()); + } + +EXPORT_C void CEikLabel::SetFont(const CFont* aFont) + { + iFont=aFont; + } + +EXPORT_C TSize CEikLabel::CalcMinimumSize(TPtrC& aText) const + { + // HeightInPixels does not modify aText. + const TInt height = HeightInPixels(aText); + + // Note that WidthInPixels modifies aText and so + // it must be called after HeightInPixels. + const TInt width = WidthInPixels(aText); + return TSize( width, height ); + } + +EXPORT_C void CEikLabel::SetEmphasis(TTextEmphasis aEmphasis) + { + iLabFlags&=(~KTextEmphasisMask); + iLabFlags|=aEmphasis; + } + +EXPORT_C TSize CEikLabel::MinimumSize() + { + __ASSERT_ALWAYS(iText,Panic(EEikPanicLabelNullText)); + TPtrC ptr=(*iText); + iSize=TSize(WidthInPixels(ptr),HeightInPixels()); + return(iSize); + } + +EXPORT_C void CEikLabel::SetPixelGapBetweenLines(TInt aGap) + { + iGapBetweenLines=aGap; + } + +EXPORT_C TInt CEikLabel::PixelGapBetweenLines() const + { + return iGapBetweenLines; + } + +EXPORT_C void CEikLabel::SetUnderlining(TBool aUnderLining) + { + if (aUnderLining) {iLabFlags|=EUnderlining;} + else iLabFlags&=(~EUnderlining); + } + +EXPORT_C void CEikLabel::SetStrikethrough(TBool aStrikethrough) + { + if (aStrikethrough) {iLabFlags|=EStrikethrough;} + else iLabFlags&=(~EStrikethrough); + } + +EXPORT_C TInt CEikLabel::BufferReserveLength() const + { + return (iLabFlags&KTextBufferReserveLength? iReserveLength : 0); + } + +EXPORT_C void CEikLabel::UseLogicalToVisualConversion( TBool aUseConversion ) + { + if ( aUseConversion ) + { + iLabFlags |= EUseLogicalToVisualConversion; + } + else + { + iLabFlags &= (~EUseLogicalToVisualConversion); + } + } + +EXPORT_C TBool CEikLabel::LogicalToVisualConversionUsed() const + { + return iLabFlags & EUseLogicalToVisualConversion; + } + +EXPORT_C void CEikLabel::EnablePictographsL( CAknPictographInterface& aInterface ) + { + if ( !iExtension ) + { + iExtension = CEikLabelExtension::NewL(); + } + + iExtension->iPictographInterface = &aInterface; + } + +EXPORT_C void CEikLabel::DisablePictographs() + { + if ( iExtension ) + { + iExtension->iPictographInterface = NULL; + } + } + +void CEikLabel::SetupGcForEmphasis(CGraphicsContext& aGc) const + { + TRgb penColor; + TRgb brushColor; + + penColor = (iEikonEnv->ControlColor(EColorLabelTextEmphasis,*this)); + if ((iLabFlags&KTextEmphasisMask) == EFullEmphasis) + { + brushColor = (iEikonEnv->ControlColor(EColorLabelHighlightFullEmphasis,*this)); + } + else + { + brushColor = (iEikonEnv->ControlColor(EColorLabelHighlightPartialEmphasis,*this)); + } + + aGc.SetPenColor(penColor); + aGc.SetBrushColor(brushColor); + aGc.SetBrushStyle(CGraphicsContext::ESolidBrush); + } + +TBool CEikLabel::CheckAndCreateExtension() + { + if (!iExtension) + { + TRAP_IGNORE(iExtension = CEikLabelExtension::NewL()); + } + return (iExtension != NULL); + } + +/** + * Writes the internal state of the control and its components to aStream. + * Does nothing in release mode. + * Designed to be overidden and base called by subclasses. + * + * @internal + * @since App-Framework_6.1 + */ +#ifndef _DEBUG +EXPORT_C void CEikLabel::WriteInternalStateL(RWriteStream&) const + {} +#else +EXPORT_C void CEikLabel::WriteInternalStateL(RWriteStream& aWriteStream) const + { + _LIT(KLitEikLblCtlStart, ""); + _LIT(KLitEikLblCtlEnd, "<\\CEikLabel>"); + + _LIT(KLitEikLblTxt,""); + _LIT(KLitEikLblTxtEnd,"<\\iText>"); + _LIT(KLitEikLblFnt,""); + _LIT(KLitEikLblFntEnd,"<\\iFont>"); + _LIT(KLitEikLblNoLns,""); + _LIT(KLitEikLblNoLnsEnd,"<\\iNumberOfLines>"); + _LIT(KLitEikLblFlgs,""); + _LIT(KLitEikLblFlgsEnd,"<\\iLabFlags>"); + _LIT(KLitEikLblGpBtwnLns,""); + _LIT(KLitEikLblGpBtwnLnsEnd,"<\\iGapBetweenLines>"); + _LIT(KLitEikLblResLen,""); + _LIT(KLitEikLblResLenEnd,"<\\iReserveLength>"); + + aWriteStream << KLitEikLblCtlStart; + aWriteStream << KLitEikLblTxt; + if(iText) + aWriteStream.WriteL(*iText); + aWriteStream << KLitEikLblTxtEnd; + aWriteStream << KLitEikLblFnt; + const TFontSpec& spec=iFont->FontSpecInTwips(); + aWriteStream << spec; + aWriteStream << KLitEikLblFntEnd; + aWriteStream << KLitEikLblNoLns; + aWriteStream.WriteInt32L(iNumberOfLines); + aWriteStream << KLitEikLblNoLnsEnd; + aWriteStream << KLitEikLblFlgs; + aWriteStream.WriteInt32L(iLabFlags); + aWriteStream << KLitEikLblFlgsEnd; + aWriteStream << KLitEikLblGpBtwnLns; + aWriteStream.WriteInt32L(iGapBetweenLines); + aWriteStream << KLitEikLblGpBtwnLnsEnd; + aWriteStream << KLitEikLblResLen; + aWriteStream.WriteInt32L(iReserveLength); + aWriteStream << KLitEikLblResLenEnd; + CEikAlignedControl::WriteInternalStateL(aWriteStream); + aWriteStream << KLitEikLblCtlEnd; + } +#endif + +EXPORT_C void CEikLabel::HandlePointerEventL(const TPointerEvent& aPointerEvent) + { + CEikAlignedControl::HandlePointerEventL(aPointerEvent); + } + +EXPORT_C void* CEikLabel::ExtensionInterface( TUid /*aInterface*/ ) + { + return NULL; + } + +EXPORT_C void CEikLabel::Reserved_2() + {} + +// @todo use some utility +#define max(a, b) a > b ? a : b; +#define min(a, b) a < b ? a : b; +#define abs(a) a < 0 ? -a : a; + +TInt CalculateLuminance(const TRgb& aColor) + { + TInt R = aColor.Red(); + TInt G = aColor.Green(); + TInt B = aColor.Blue(); + // Should be scaled to 0-255? + TInt Y = (((66 * R) + (129 * G) + (25 * B) + 128) >> 8) + 16; + return Y; + } + +void CEikLabel::ConvertColorsForOutlineEffect(TRgb& aPenColor, TRgb& aBrushColor) const + { + // the caller intends the brush color to be the background or outline, + // and the pen color to be the foreground color + TRgb innerColor = aPenColor; + TRgb outerColor = aBrushColor; + + // @todo maybe there is already some conversion utility in multimedia image library? + TInt innerLum = CalculateLuminance(innerColor); + TInt outerLum = CalculateLuminance(outerColor); + + // if the defined colours are the same, then change the outline color so that + // it's either black or white, contrasting according to the font label text color's brightness + TInt difference = outerLum - innerLum; + difference = abs(difference); + TInt half = (0xff / 2); // @todo figure out hlsMax somehow + TInt threshold = (0xff / 3); // @todo figure out hlsMax somehow, and decide on the threshold! + if(difference < threshold) + { + // if inner luminance is low, the outer luminance should be high, i.e. white + outerColor = (innerLum < half) ? KRgbWhite : KRgbBlack; + } + + // for outline effect, we must set the color we want as the outline to the pen color, and + // the color we want as the fill to the brush color, so swap them round + aPenColor = outerColor; + aBrushColor = innerColor; + } + +