diff -r 000000000000 -r 2f259fa3e83a lafagnosticuifoundation/cone/src/coetextdrawer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lafagnosticuifoundation/cone/src/coetextdrawer.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,924 @@ +// Copyright (c) 2004-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 + + +// +// class XCoeTextDrawer +// +const TInt KDefaultLineGap = 1; + + +// +// class CCoeTextDrawerBaseExt +// + +/** +This extension block is used to to avoid BC breaks in adding to the +main data structures. +@internalComponent +*/ +NONSHARABLE_CLASS(CCoeTextDrawerBaseExt) : public CBase + { +public: + static CCoeTextDrawerBaseExt* New(); + ~CCoeTextDrawerBaseExt(); + + void SetAppLanguage(TLanguage aAppLang); + TBidiText::TDirectionality DirectionalityToConsider(const TCoeTextTypeAdaptor& aText) const; +private: + CCoeTextDrawerBaseExt(); + TInt Construct(); +private: + enum TScriptDirectionality + { + EScriptDirUndefined, + EScriptDirLeftToRight, + EScriptDirRightToLeft + }; +private: + TScriptDirectionality iAppScriptDirectionality; + }; + +/** +Create a CCoeTextDrawerBaseExt object. +*/ +CCoeTextDrawerBaseExt* CCoeTextDrawerBaseExt::New() + { + CCoeTextDrawerBaseExt* self = new CCoeTextDrawerBaseExt(); + if(self->Construct() != KErrNone) + { + delete self; + self = NULL; + } + + return self; + } + +/** +Constructor. +*/ +CCoeTextDrawerBaseExt::CCoeTextDrawerBaseExt() + {} + +/** +Destructor. +*/ +CCoeTextDrawerBaseExt::~CCoeTextDrawerBaseExt() + {} + +/** +Second-phase object construction. +*/ +TInt CCoeTextDrawerBaseExt::Construct() +//lint --e{1762} Suppress member function could be made const + { + return KErrNone; + } + +/** +Set the application language directionality based on the TLanguage passed as argument. +Passing ELangNone will set the application language directionality to "undefined". +*/ +void CCoeTextDrawerBaseExt::SetAppLanguage(TLanguage aAppLang) + { + if(aAppLang == ELangNone) + iAppScriptDirectionality = EScriptDirUndefined; + else if (TBidiText::ScriptDirectionality(aAppLang) == TBidiText::ELeftToRight) + iAppScriptDirectionality = EScriptDirLeftToRight; + else + iAppScriptDirectionality = EScriptDirRightToLeft; + } + +/** +Return the language directionality to consider when deciding whether to swap left and right alignment +(for non-absolute horizontal alignment, left and right shall be swapped for scrips with RightToLeft +directionality, such as Arabic). + +If the application language has been set using SetAppLanguage(), the directionality of the languange that the +application is currently running in will be used. If not, the directionality of the actual text being printed +at the moment will be used. +*/ +TBidiText::TDirectionality CCoeTextDrawerBaseExt::DirectionalityToConsider(const TCoeTextTypeAdaptor& aText) const + { + TBidiText::TDirectionality textDirectionality = TBidiText::ELeftToRight; + if(iAppScriptDirectionality == EScriptDirRightToLeft) + textDirectionality = TBidiText::ERightToLeft; + else if(iAppScriptDirectionality == EScriptDirUndefined) + textDirectionality = (aText.HasRightToLeftDirectionality() ? TBidiText::ERightToLeft : TBidiText::ELeftToRight); + + return textDirectionality; + } + + +// +// Class XCoeTextDrawer +// + + +/** +Use this constructor to create a XCoeTextDrawer object on the stack, inside your control's +Draw() method. The XCoeTextDrawer object will work as a smart-pointer to the CCoeTextDrawerBase +object, managing its life. Get the CCoeTextDrawerBase-derived object to use by calling +CCoeControl::TextDrawer(). Do not create a new CCoeTextDrawerBase-derived object inside the +Draw() method. If you want to change the text drawer used by the control or any of the control's +children, override the CCoeControl::GetTextDrawer() method. Inside it you can create a new +CCoeTextDrawerBase object or change the properties of the CCoeTextDrawerBase object passed to it. +*/ +EXPORT_C XCoeTextDrawer::XCoeTextDrawer(CCoeTextDrawerBase& aTextDrawer) + : iTextDrawer(&aTextDrawer) + { + iClipRect = TRect(); + } + + +/** +Destructor. The XCoeTextDrawer object work as a smart-pointer object to the CCoeTextDrawerBase +object actually performing the text drawing. The XCoeTextDrawer object shall be allocated on +the stack (i.e. not using "new") in the CCoeControl's Draw() method. Once the XCoeTextDrawer object +goes out of scope, this destructor will be called. It will call Reset() on the CCoeTextDrawerBase +object, if it was been set to be resuable by its owner. If not, the CCoeTextDrawerBase object +will be deleted. Note that it is up to the creator/owner of the CCoeTextDrawerBase to decide +whether it shall be reusable or not. A user of the XCoeTextDrawer must not change the re-use'ness +of the CCoeTextDrawerBase. +*/ +EXPORT_C XCoeTextDrawer::~XCoeTextDrawer() + { + if(iTextDrawer && iTextDrawer->IsReusable()) + iTextDrawer->Reset(); + else + delete iTextDrawer; + } + +/** +Assignment operator for CCoeTextDrawerBase objects. + +Due to compiler defect/feature, this method may not work. +I.e. if + XCoeTextDrawer textDrawer = TextDrawer(); +does not compile, restate as + XCoeTextDrawer textDrawer(TextDrawer()); + +@param aTextDrawer A text drawer. +*/ +EXPORT_C void XCoeTextDrawer::operator=(CCoeTextDrawerBase& aTextDrawer) + { + // The currently owned CCoeTextDrawerBase object may be reusable and should just + // be reset rather than deleted. + if(iTextDrawer && iTextDrawer->IsReusable()) + iTextDrawer->Reset(); + else + delete iTextDrawer; + + iTextDrawer = &aTextDrawer; + } //lint !e1539 Suppress Member 'XCoeTextDrawer::iClipRect' not assigned by assignment operator + +/** +Deprecated. +*/ +EXPORT_C CCoeTextDrawerBase * XCoeTextDrawer::operator ->() + { + return iTextDrawer; + } + +/** +An XCoeTextDrawer object should not be copied as only one handle should exist to a CCoeTextDrawer. +Therefore this copy constructor is private and just contains a panic statement. +@internalComponent +*/ +XCoeTextDrawer::XCoeTextDrawer(const XCoeTextDrawer& /*aTextDrawer*/) + { + ASSERT(0); + } //lint !e1744 Suppress Member 'XCoeTextDrawer::iTextDrawer' possibly not initialized by private constructor + +/** +Call this method to draw text contained i a TBidiText object. This is the +recommended way of drawing any widget text, as it will manage both left-to-right +scripts like English as well as right-to-left scripts such as Arabic and Hebrew. + +Before calling this method, be sure to set the text alignment, margins, clip rect, +etc using the XCoeTextDrawer methods SetAlignment(), SetMargins(), and SetClipRect(). + +Note that before a TBidiText text can be drawn, it has to be line-broken using +TBidiText::WrapText() with a wrap width that match the text rect minus margins. + +@param aGc The graphics context. +@param aText TBidiText reference containing the text to be drawn. +@param aTextRect Rectangle text will be drawn in +@param aFont Font to be used. +*/ +EXPORT_C void XCoeTextDrawer::DrawText(CGraphicsContext& aGc, const TBidiText& aText, const TRect& aTextRect, const CFont& aFont) const + { + ASSERT(iTextDrawer); + iTextDrawer->DrawText(aGc, TCoeTextTypeAdaptor(aText), aFont, aTextRect, iClipRect); + } + +/** +Call this method to draw vertical text contained in a TBidiText object. This is the +recommended way of drawing any widget text, as it will manage both left-to-right +scripts like English as well as right-to-left scripts such as Arabic and Hebrew. + +Before calling this method, be sure to set the text alignment, margins, clip rect, +etc using the XCoeTextDrawer methods SetAlignment(), SetMargins(), and SetClipRect(). + +Note that before a TBidiText text can be drawn, it has to be line-broken using +TBidiText::WrapText() with a wrap width that match the text rect minus margins. + +Also note that the margines are relative to the orientation of the text. + +@param aGc The graphics context. +@param aText TBidiText reference containing the text to be drawn. +@param aTextRect Rectangle text will be drawn in +@param aFont Font to be used. +@param aUp ETrue, text is rotated 90 degrees anti-clockwise; EFalse, text is rotated 90 degrees clockwise. +@see XCoeTextDrawer::SetClipRect +*/ +EXPORT_C void XCoeTextDrawer::DrawTextVertical(CGraphicsContext& aGc, const TBidiText& aText, const TRect& aTextRect, const CFont& aFont, TBool aUp) const + { + ASSERT(iTextDrawer); + iTextDrawer->DrawTextVertical(aGc, TCoeTextTypeAdaptor(aText), aFont, aTextRect, iClipRect, aUp); + } + +/** +Low level text drawing is always performed left-to-right on the screen. This +means that for any script with right-to-left directionality (like Arabic), +the in-memory order of the glyphs has to be changed (reordered) from the +logical order (start of sentence first, before end of sentence) to the +display order (end of sentence before (i.e. left of) start of sentence). +This operation is performed by TBidiText. + +However, sometimes text is reordered through some other means than the TBidiText +class. In these cases, this method can be used to draw the text contained in a +descriptor object in the same order (left-to-right) as it appears in the descriptor +memory. I.e. this method assumes that the text has already been changed into the +display order. If this is not the case, and the text is in a right-to-left script, +it will come out backwards. + +@param aGc The graphics context. +@param aText TDesC reference containing the text to be drawn. +@param aTextRect Rectangle text will be drawn in +@param aFont Font to be used. +*/ +EXPORT_C void XCoeTextDrawer::DrawDisplayOrderedText(CGraphicsContext& aGc, const TDesC& aText, const TRect& aTextRect, const CFont& aFont) const + { + ASSERT(iTextDrawer); + iTextDrawer->DrawText(aGc, aText, aFont, aTextRect, iClipRect); + } + +/** +Low level text drawing is always performed left-to-right on the screen. This +means that for any script with right-to-left directionality (like Arabic), +the in-memory order of the glyphs has to be changed (reordered) from the +logical order (start of sentence first, before end of sentence) to the +display order (end of sentence before (i.e. left of) start of sentence). +This operation is performed by TBidiText. + +However, sometimes text is reordered through some other means than the TBidiText +class. In these cases, this method can be used to draw the text contained in a +descriptor object in the same order (left-to-right) as it appears in the descriptor +memory. I.e. this method assumes that the text has already been changed into the +display order. If this is not the case, and the text is in a right-to-left script, +it will come out backwards. + +Note that the margines are relative to the orientation of the text. + +@param aGc The graphics context. +@param aText TDesC reference containing the text to be drawn. +@param aTextRect Rectangle text will be drawn in +@param aFont Font to be used. +*/ +EXPORT_C void XCoeTextDrawer::DrawDisplayOrderedTextVertical(CGraphicsContext& aGc, const TDesC& aText, const TRect& aTextRect, const CFont& aFont, TBool aUp) const + { + ASSERT(iTextDrawer); + iTextDrawer->DrawTextVertical(aGc, aText, aFont, aTextRect, iClipRect, aUp); + } + +/** +Return the clip rect that will be used by DrawText() and DrawDisplayOrderedText(). +Any text falling outside this rectangle will not be visible. This is used to crop text. + +@return The clipping rect. +*/ +EXPORT_C TRect XCoeTextDrawer::ClipRect() const + { + return iClipRect; + } + +/** +Set the clip rect that will be used by DrawText() and DrawDisplayOrderedText(). +Any text falling outside this rectangle will not be visible. This is used to crop text. + +@param aClipRect TRect value to set iClipRect to. +*/ +EXPORT_C void XCoeTextDrawer::SetClipRect(const TRect& aClipRect) + { + iClipRect = aClipRect; + } + + +// +// class CCoeTextDrawerBase +// + +/** +Constructor. +*/ +EXPORT_C CCoeTextDrawerBase::CCoeTextDrawerBase() + { + Reset(); // N.B. This will always call local implementation, never derived overrides + } //lint !e1506 Supress Call to virtual function 'Reset(void)' within constructor + +/** +This method is called from the destructor of the XCoeTextDrawer object managing the +life of the CCoeTextDrawerBase object, if the CCoeTextDrawerBase object has been set +to be reusable (by its owner calling SetReusable()). + +Any derived class must override this method to reset its drawing parameters to their +defaults, so that the object is ready to be used again. Any overriding implementation +must call the base implementation as well. +*/ +EXPORT_C void CCoeTextDrawerBase::Reset() + { + // Don't change iIsReusable! + iAlignment = EHLeftVTop; + iMargins = TMargins8(); + iLineGap = KDefaultLineGap; + } + +/** +Destructor. +*/ +EXPORT_C CCoeTextDrawerBase::~CCoeTextDrawerBase() + { + delete iExtension; + } + +/** +Second phase object construction. +Note that this method is non-leaving as it may be called indirectly from a Draw() +method, which must not leave. + +@return returns KErrNone if successful, otherwise KErrNoMemory. +*/ +EXPORT_C TInt CCoeTextDrawerBase::Construct() + { + // allocate extension block + iExtension = CCoeTextDrawerBaseExt::New(); + + if (!iExtension) + return KErrNoMemory; + else + return KErrNone; + } + +/** +Unless absolute horizontal aligment has been selected (see TGulAlignment), the actual +horizontal text alignment used when drawing text depends on whether the directionality +of the scrip is left-to-right or right-to-left. In the latter case left and right +is swapped. By default, the directionality of the actual text being drawn will define +whether the horizontal alignment will be swapped or not. However, if (as recommended) the +directionality of the application's main language shall be considered instead (rather +than the directionality of the text being printed at the moment), then call this method. + +If ELangNone is specified, the text drawer will be reset to swap horizontal alignment +depending on the directionality of the text being printed. + +@param aAppLang The application language (e.g. from CEikonEnv::ApplicationLanguage()). +*/ +EXPORT_C void CCoeTextDrawerBase::SetAppLanguage(TLanguage aAppLang) + { + if(iExtension) + iExtension->SetAppLanguage(aAppLang); + } + +/** +This method returns the actual (absolute) horizontal text alignment to be used +when drawing text in any CCoeTextDrawerBase-derived DrawText() implementation. +The actual alignment depends on the application language directionality if the +application language has been set calling CCoeTextDrawerBase::SetAppLanguage(), +or otherwise on the directionality of the actual text being printed. If the +directionality is right-to-left (and the horizontal alignment has not been set +to be absolute, using TGulAlignment::SetAbsoluteHAlignment()), left and right +alignment (set using XCoeTextDrawer::SetAlignment()) will be swapped. +*/ +EXPORT_C TGulHAlignment CCoeTextDrawerBase::ActualHorizontalAlignment(const TCoeTextTypeAdaptor& aText) const + { + if(iAlignment.HasAbsoluteHAlignment()) + return iAlignment.HAlignment(); + + if(iExtension) + { + const TBidiText::TDirectionality directionalityToConsider = iExtension->DirectionalityToConsider(aText); + return iAlignment.HAlignment(directionalityToConsider); + } + else + return iAlignment.HAlignment(); + } + +// Accessor/Set Methods + +/** +Returns whether the CCoeTextDrawerBase-derived text drawer object has been set +to be reusable or not. If reusable, the text drawer is assumed to have an owner +that will delete it when appropriate. If not reusable, the XCoeTextDrawer will +delete it in its destructor. + +@return bool value of iIsReusable data member +*/ +EXPORT_C TBool CCoeTextDrawerBase::IsReusable() const + { + return iIsReusable; + } + +/** +Set whether the text drawer is reusable or not. A reusable text drawer will be +reset (through a call to Reset()) rather than deleted when the XCoeTextDrawer +referring to it is deleted. This decision has to be made by the creator of the +CCoeTextDrawerBase object. I.e. this method must not be called by a mere user +of the XCoeTextDrawer. + +@param aIsReusable Boolean indicating whether the text drawer can be re-used. +*/ +EXPORT_C void CCoeTextDrawerBase::SetReusable(TBool aIsReusable) + { + iIsReusable = aIsReusable; + } + +/** +Returns the text alignment that will be used by DrawText() and DrawDisplayOrderedText(). +Note that left and right alignment will be swapped for right-to-left scripts, unless +the alignment has been set to be absolute (see TGulAlignment). + +A typical user of the text drawer mechanism will use the XCoeTextDrawer version of this API. + +@return TGulAlignment value of iAlignment data member +*/ +EXPORT_C TGulAlignment CCoeTextDrawerBase::Alignment() const + { + return iAlignment; + } + +/** +Set the text alignment that will be used by DrawText() and DrawDisplayOrderedText(). +Note that left and right alignment will be swapped for right-to-left scripts, unless +the alignment has been set to be absolute (see TGulAlignment). + +A typical user of the text drawer mechanism will use the XCoeTextDrawer version of this API. + +@param aAlignment TGulAlignment value. +*/ +EXPORT_C void CCoeTextDrawerBase::SetAlignment(const TGulAlignment& aAlignment) + { + iAlignment = aAlignment; + } + +/** +Returns the text margins that will be used by DrawText() and DrawDisplayOrderedText(). + +A typical user of the text drawer mechanism will use the XCoeTextDrawer version of this API. + +@return The margins between the text rect and the actual text, in pixels. +*/ +EXPORT_C TMargins8 CCoeTextDrawerBase::Margins() const + { + return iMargins; + } + +/** +Set the text margins that will be used by DrawText() and DrawDisplayOrderedText(). + +A typical user of the text drawer mechanism will use the XCoeTextDrawer version of this API. + +@param aMargins The margins between the text rect and the actual text, in pixels. +*/ +EXPORT_C void CCoeTextDrawerBase::SetMargins(const TMargins8& aMargins) + { + iMargins = aMargins; + } + +/** +Returns the gap (in pixels) between lines of text. Default gap is 1 (one) pixel. + +A typical user of the text drawer mechanism will use the XCoeTextDrawer version of this API. + +@return The gap between lines of text, in pixels. +*/ +EXPORT_C TInt CCoeTextDrawerBase::LineGapInPixels() const + { + return iLineGap; + } + +/** +Set the gap (in pixels) between lines of text. Default gap is 1 (one) pixel. + +A typical user of the text drawer mechanism will use the XCoeTextDrawer version of this API. + +@param aLineGapInPixels The gap between lines of text, in pixels. +*/ +EXPORT_C void CCoeTextDrawerBase::SetLineGapInPixels(TInt aLineGapInPixels) + { + iLineGap = aLineGapInPixels; + } + +/** +Any text drawer implementation must override this method, returning the "margins" +that the text effect will add to the text extent. I.e. a one-pixel drop-shadow +to the lower right will add an effect margin of TMargins8(0,0,1,1), while a +one-pixel all-around outline will add an effect margin of TMargins8(1,1,1,1). +*/ +EXPORT_C TMargins8 CCoeTextDrawerBase::EffectMargins() + { + return TMargins8(); + } + +/** +Draws the vertical text provided as parameter. + +@param aGc The graphics context. +@param aText The TCoeTextTypeAdaptor text object to draw. +@param aFont Font to be used for drawing the text. +@param aTextRect The rectangle to draw the text in. +@param aClipRect The clipping rectangle. +@param aUp ETrue, text is rotated 90 degrees anti-clockwise; EFalse, text is rotated 90 degrees clockwise. +*/ +EXPORT_C void CCoeTextDrawerBase::DrawTextVertical(CGraphicsContext& aGc, const TCoeTextTypeAdaptor& aText, const CFont& aFont, + const TRect& aTextRect, const TRect& aClipRect, TBool aUp) const + { + const TInt lineSpacing = aFont.FontMaxHeight() + LineGapInPixels(); + const TInt textHeightInPixels = (aText.NumberOfLines() * lineSpacing) - LineGapInPixels(); // Center the ascent + + // Calculate the text's "left point", i.e. the point on the baseline where the text starts + TPoint leftPoint = Margins().InnerRect(aTextRect).iTl + TPoint(0,aFont.FontMaxAscent()); + const TInt deltaHeight = aTextRect.Width() - Margins().SizeDelta().iHeight - textHeightInPixels; + if (deltaHeight > 0) + { + switch(Alignment().VAlignment()) + { + case EVTop: + break; + case EVBottom: + leftPoint.iY += deltaHeight; + break; + case EVCenter: + leftPoint.iY += deltaHeight >> 1; + break; + } + } + + // Set up the GC + aGc.UseFont(&aFont); + aGc.SetBrushStyle(CBitmapContext::ENullBrush); + aGc.SetPenStyle(CBitmapContext::ESolidPen); + aGc.SetPenColor(TextColor()); + + // Compensate textRect for ClipRect + TRect textRect = aTextRect; + if(!(aClipRect.IsEmpty()) && aClipRect != aTextRect) + { + textRect.Intersection(aClipRect); + } + + // Use leftMargin and baseline to position each text line correctly, + // taking margins, alignment, and line spacing into account + TInt baseline = leftPoint.iY - textRect.iTl.iY; + + // Draw the lines + const TInt lines = lineSpacing == 0 ? 1 : aText.NumberOfLines(); + const TGulHAlignment actualHorizontalAlignment = ActualHorizontalAlignment(aText); + for (TInt i = 0; i < lines; ++i) + { + TInt width = 0; + TPtrC textLine = aText.LineOfText(i, width, aFont); + TInt margin = leftPoint.iX - textRect.iTl.iX; + if (actualHorizontalAlignment != EHLeft) + { + const TInt wrapWidth = aTextRect.Height() - Margins().SizeDelta().iWidth; + const TInt excess = wrapWidth - width; + margin += actualHorizontalAlignment != EHCenter ? excess : excess >> 1; + } + aGc.DrawTextVertical(textLine, textRect, baseline, aUp, CGraphicsContext::ELeft, margin); + baseline += lineSpacing; + } + + aGc.DiscardFont(); + } + +// For future use +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved3() { } +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved4() { } +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved5() { } +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved6() { } +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved7() { } +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved8() { } +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved9() { } +/** @internalComponent */ +EXPORT_C void CCoeTextDrawerBase::CCoeTextDrawerBase_Reserved10() { } + + + +// +// class CCoePlainTextDrawer +// + +/** +Created a new plain text drawer on the heap. This shall typically be done in the +CCoeControl::GetTextDrawer() method, or better, in the constructor of the owner +of the text drawer. + +Do not call this method from within a CCoeControl::Draw() method. If all you want +is access to a text drawer, call CCoeControl::TextDrawer(). + +@param aTextColor The color that will be used to draw text. +@return A new CCoePlainTextDrawer instance or null if the creation of a new instance failed. +*/ +EXPORT_C CCoePlainTextDrawer* CCoePlainTextDrawer::New(TRgb aTextColor) + { + CCoePlainTextDrawer* self = new CCoePlainTextDrawer(aTextColor); + + if(self && self->Construct() == KErrNone) + return self; // Successful allocation + else + { + delete self; + return NULL; // Error in allocation + } + } + +/** +Second-phase construction. This method is non-leaving as it will have been called indirectly +from a control's draw method which cannot leave. +@return KErrNone if the function executed without errors, any other standard error code if the +function failed. +*/ +TInt CCoePlainTextDrawer::Construct() + { + return CCoeTextDrawerBase::Construct(); + //lint --e{1762} Suppress member function could be made const + } + +/** +See CCoeTextDrawerBase::TextColor(). + +@see CCoeTextDrawerBase +*/ +EXPORT_C TRgb CCoePlainTextDrawer::TextColor() const + { + return iTextColor; + } + +/** +See CCoeTextDrawerBase::SetTextColor(). + +@see CCoeTextDrawerBase +*/ +EXPORT_C void CCoePlainTextDrawer::SetTextColor(TRgb aTextColor) + { + iTextColor = aTextColor; + } + +/** +Constructor. +*/ +CCoePlainTextDrawer::CCoePlainTextDrawer(TRgb aTextColor) : + iTextColor(aTextColor) + { + } + +/** +This function is defined by the MObjectProvider class. +It allows the actual type of text drawer to be identified. + +@param aId The type of the desired object. +@return A pointer to an object. +@see MObjectProvider +*/ +EXPORT_C TTypeUid::Ptr CCoePlainTextDrawer::MopSupplyObject(TTypeUid aId) + { + if (aId.iUid == ETypeId) + return aId.MakePtr(this); + else + return TTypeUid::Null(); + } + +/** +See CCoeTextDrawerBase::Reset(). +*/ +void CCoePlainTextDrawer::Reset() + { + CCoeTextDrawerBase::Reset(); + iTextColor = KRgbBlack; + } + +/** +Draws the text provided as parameter. + +@param aGc The graphics context. +@param aText The TCoeTextTypeAdaptor text object to draw. +@param aFont Font to be used for drawing the text. +@param aTextRect The rectangle to draw the text in. +@param aClipRect The clipping rectangle. + +@return void +@see CCoeTextDrawerBase +*/ +void CCoePlainTextDrawer::DrawText(CGraphicsContext& aGc, const TCoeTextTypeAdaptor& aText, const CFont& aFont, + const TRect& aTextRect, const TRect& aClipRect) const + { + const TInt lineSpacing = aFont.FontMaxHeight() + LineGapInPixels(); + const TInt textHeightInPixels = (aText.NumberOfLines() * lineSpacing) - LineGapInPixels(); // Center the ascent + + // Calculate the text's "left point", i.e. the point on the baseline where the text starts + TPoint leftPoint = Margins().InnerRect(aTextRect).iTl + TPoint(0,aFont.FontMaxAscent()); + const TInt deltaHeight = Margins().InnerRect(aTextRect).Height() - textHeightInPixels; + if (deltaHeight > 0) + { + switch(Alignment().VAlignment()) + { + case EVTop: + break; + case EVBottom: + leftPoint.iY += deltaHeight; + break; + case EVCenter: + leftPoint.iY += (deltaHeight >> 1); // /2 + break; + } + } + + // Set up the GC + aGc.UseFont(&aFont); + aGc.SetBrushStyle(CBitmapContext::ENullBrush); + aGc.SetPenStyle(CBitmapContext::ESolidPen); + aGc.SetPenColor(iTextColor); + + // Compensate textRect for ClipRect + TRect textRect = aTextRect; + if(!(aClipRect.IsEmpty())) + textRect.Intersection(aClipRect); + + // Use leftMargin and baseline to position each text line correctly, + // taking margins, alignment, and line spacing into account + TInt baseline = leftPoint.iY - textRect.iTl.iY; + + const TGulHAlignment actualHorizontalAlignment = ActualHorizontalAlignment(aText); + + // Draw the lines + const TInt lines = lineSpacing == 0 ? 1 : aText.NumberOfLines(); + for (TInt i = 0; i < lines; ++i) + { + TInt width = 0; + TPtrC textLine = aText.LineOfText(i, width, aFont); + TInt leftMargin = leftPoint.iX - textRect.iTl.iX; + if (actualHorizontalAlignment != EHLeft) + { + const TInt wrapWidth = aTextRect.Width() - Margins().SizeDelta().iWidth; + const TInt excess = wrapWidth - width; + leftMargin += actualHorizontalAlignment != EHCenter ? excess : excess >> 1; + } + + aGc.DrawText(textLine, textRect, baseline, CGraphicsContext::ELeft, leftMargin); + baseline += lineSpacing; + } + + aGc.DiscardFont(); + } + +// +// TCoeTextTypeAdaptor +// + +/** +Constructor taking a plain descriptor as parameter. The directionality of the text separated with '\n' +must always be left-to-right display order. +@param aText The text wrapped by the TCoeTextTypeAdaptor. +*/ +EXPORT_C TCoeTextTypeAdaptor::TCoeTextTypeAdaptor(const TDesC& aText) // text separated with '\n' + { + iTextType = ENewlineSeparated; + iText = static_cast(&aText); + } + +/** +Constructor taking a TBidiText object as parameter. +@param aText The text wrapped by the TCoeTextTypeAdaptor. +*/ +EXPORT_C TCoeTextTypeAdaptor::TCoeTextTypeAdaptor(const TBidiText& aText) // TBidiText object + { + iTextType = EBidiText; + iText = &aText; + } + +const TText KCharacterLF = 0x0a; + +const TText* FindEndOfThisLine(const TText* aStart, const TText* aEnd) + { + while (aStart != aEnd && *aStart != KCharacterLF) + ++aStart; + + return aStart; + } + + +/** +Calculates the number of lines in the text. +@return TInt number of lines in the object +*/ +EXPORT_C TInt TCoeTextTypeAdaptor::NumberOfLines() const + { + switch(iTextType) + { + case ENewlineSeparated: + { + const TText* startText = static_cast(iText)->Ptr(); + const TInt length = static_cast(iText)->Length(); + const TText* endText = startText + length; + + TInt num = 0; + while (startText < endText) + { + startText = FindEndOfThisLine(startText, endText); + if (*startText == KCharacterLF && startText < endText) + { + ++startText; + } + ++num; + } + return num; + } + case EBidiText: + return static_cast(iText)->NumberOfLinesInDisplayText(); + default: + return 0; + } + } + +/** +Extracts a line of text. The width (in pixels) of the line is returned in aWidthInPixels. +@param aLineNumber Zero-based line number. +@param aWidthInPixels The width of the line of text. +@param aFont The font that will be used to draw the text. +@return TPtrC line of text +*/ +EXPORT_C TPtrC TCoeTextTypeAdaptor::LineOfText(TInt aLineNumber, TInt& aWidthInPixels, const CFont& aFont) const + { + switch(iTextType) + { + case ENewlineSeparated: + { + const TText* startText = static_cast(iText)->Ptr(); + const TInt length = static_cast(iText)->Length(); + const TText* endText = startText + length; + + for (; aLineNumber != 0; --aLineNumber) + { + startText = FindEndOfThisLine(startText, endText); + if (*startText == KCharacterLF) + ++startText; + } + const TText* endOfLine = FindEndOfThisLine(startText, endText); + TPtrC textInLineNumber(startText, endOfLine - startText); + // Calculate the width of the line according to the font used. + aWidthInPixels = aFont.TextWidthInPixels(textInLineNumber); + return textInLineNumber; + } + case EBidiText: + return static_cast(iText)->LineOfDisplayText(aLineNumber, aWidthInPixels); + default: + return KNullDesC(); + } + } + +/** +This function checks the directionality of the text. +@return ETrue if the text has right-to-left directionality, EFalse if it has left-to-right directionality. +*/ +EXPORT_C TBool TCoeTextTypeAdaptor::HasRightToLeftDirectionality() const + { + switch(iTextType) + { + case EBidiText: + return (static_cast(iText)->Directionality() == TBidiText::ERightToLeft); + default: + return EFalse; + } + }