--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_akn/lcdui/src/CMIDItemLabel.cpp Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,715 @@
+/*
+* Copyright (c) 2003-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: Used to draw the item labels and some string items. Provides
+* word wrapping and other functionality.
+*
+*/
+
+
+#include <coemain.h>
+// API for CEikLabel used in several places
+#include <eikcapc.h>
+// API for text wrapping
+#include <AknBidiTextUtils.h>
+// using CAknLayoutFont for retrieving height in pixels of each line
+#include <AknLayoutFont.h>
+// used in constructor for obtaining label color from skin
+#include <AknsDrawUtils.h>
+
+#include "CMIDControlItem.h"
+#include "CMIDGc.h"
+// using CMIDUtils::IsLineSeparator
+#include "CMIDUtils.h"
+#include "CMIDCommand.h"
+#include "CMIDForm.h"
+#include "CMIDCommandList.h"
+#include "CMIDItemLabel.h"
+#include "CMIDFont.h"
+
+// using TAknWindowLineLayout (in UpdateMargins function)
+#include <applayout.cdl.h>
+// LAF - AknLayoutScalable_Avkon::form2_midp_label_pane_cp (in UpdateMargins function)
+#include <aknlayoutscalable_avkon.cdl.h>
+
+
+CMIDItemLabel* CMIDItemLabel::NewL(TInt aMaxWidth, TBool aLabelBeforeContent,
+ TInt aMaxNumberOfLines, const CMIDFont::TDefaultId& aDefaultFontId, TBool aIsContent)
+{
+ CMIDItemLabel* self = new(ELeave) CMIDItemLabel(aMaxWidth,
+ aLabelBeforeContent, aMaxNumberOfLines, aDefaultFontId, aIsContent);
+
+ CleanupStack::PushL(self);
+ self->ConstructL();
+
+ CleanupStack::Pop(self);
+ return self;
+}
+
+CMIDItemLabel::~CMIDItemLabel()
+{
+ delete iText;
+ iText = NULL;
+ delete iWrappedText;
+ iWrappedText = NULL;
+
+ delete iWrappedArray;
+ iWrappedArray = NULL;
+
+ delete iLineWidthArray;
+ iLineWidthArray = NULL;
+
+ ResetLabelArray();
+ delete iLabelArray;
+ iLabelArray = NULL;
+
+ delete iPictographInterface;
+ iPictographInterface = NULL;
+}
+
+/** Returns the width of the ellipsis truncation character
+ and the average line height */
+TSize CMIDItemLabel::MinimumSize()
+{
+ if (iLabelBeforeContent)
+ {
+ return TSize(Font()->CharWidthInPixels(KEllipsis) + iLabelMargins.iLeft
+ + iLabelMargins.iRight,
+ LineHeight() + iLabelMargins.iTop);
+ }
+ else
+ {
+ return TSize(Font()->CharWidthInPixels(KEllipsis) + iLabelMargins.iLeft
+ + iLabelMargins.iRight,
+ LineHeight() + iLabelMargins.iBottom);
+ }
+
+}
+
+TInt CMIDItemLabel::CountComponentControls() const
+{
+ return iLabelArray->Count();
+}
+
+CCoeControl* CMIDItemLabel::ComponentControl(TInt aIndex) const
+{
+ return (*iLabelArray)[aIndex];
+}
+
+/**
+Returns the preferred size, this is not the one given by the
+application but the size that allows the text to be displayed
+without wrapping at word level but only wrapping at line level.
+*/
+TSize CMIDItemLabel::PreferredSize() const
+{
+ if (iLabelBeforeContent)
+ {
+ return TSize(PreferredWidth(), LineHeight() + iLabelMargins.iTop);
+ }
+ else
+ {
+ return TSize(PreferredWidth(), LineHeight() + iLabelMargins.iBottom);
+ }
+}
+
+// it is up to the component changing the text to tell the form to update. This will lead to
+// the label being re-wrapped
+void CMIDItemLabel::SetTextL(const TDesC& aText)
+{
+ delete iText;
+ iText = NULL;
+
+ iText = aText.AllocL();
+
+ iWrappedArray->Reset();
+ ResetLabelArray();
+
+ delete iWrappedText;
+ iWrappedText = NULL;
+
+}
+
+/**
+ Return the width of the longest line amongst those
+ allowed by iMaxNumberOfLines
+*/
+TInt CMIDItemLabel::PreferredWidth() const
+{
+ return Min((LongestLineWidth() + iLabelMargins.iLeft + iLabelMargins.iRight), iMaxWidth);
+}
+
+/** Return the width of the longest line as long as this line
+ is not beyond iMaxNumberOfLines. If we haven't exausted
+ all the text we add the width of the ellipses truncation indicator.
+ */
+TInt CMIDItemLabel::LongestLineWidth() const
+{
+ if (!iText)
+ {
+ return Font()->CharWidthInPixels(KEllipsis);
+ }
+
+ TInt length = iText->Length();
+ TInt width = 0;
+ TBool inLine = EFalse;
+ TInt lineStartIdx = 0;
+ TInt numLines = 0;
+
+ for (TInt i=0; i < length; i++)
+ {
+ if (!IsLineSeparator((*iText)[i]) && !inLine)
+ {
+ inLine = ETrue;
+ lineStartIdx = i;
+ }
+ else if (IsLineSeparator((*iText)[i]) && inLine)
+ {
+ inLine = EFalse;
+ numLines++;
+
+ TPtrC ptr = iText->Mid(lineStartIdx, i - lineStartIdx);
+ TInt w = Font()->TextWidthInPixels(ptr);
+ if (w > width)
+ {
+ width = w;
+ }
+ }
+ else if (inLine && (i == (length - 1)))
+ {
+ inLine = EFalse;
+ TPtrC ptr = iText->Mid(lineStartIdx, (i - lineStartIdx) + 1);
+ TInt w = Font()->TextWidthInPixels(ptr);
+ if (w > width)
+ {
+ width = w;
+ }
+ }
+
+ if ((iMaxNumberOfLines > 0) && (numLines >= iMaxNumberOfLines))
+ {
+ if (i != (length - 1))
+ {//if there is still text add space for ellipsis truncation
+ width += Font()->CharWidthInPixels(KEllipsis);
+ }
+ break;
+ }
+ }
+
+ return width;
+}
+
+/**
+ * Returns the height in pixels of each line
+ */
+TInt CMIDItemLabel::LineHeight() const
+{
+ const CAknLayoutFont* layoutFont = CAknLayoutFont::AsCAknLayoutFontOrNull(Font());
+
+ TInt height = 0;
+ if (layoutFont)
+ {
+ // Calculate height of one line
+ height += layoutFont->TextPaneHeight();
+ }
+ else
+ {
+ height += Font()->HeightInPixels();
+ }
+ return height;
+}
+
+/**
+ * Prepare the line width array to the case of all lines having the same
+ * width and then call WrapTextAndSetSizeL()
+ *
+ * @see WrapTextAndSetSizeL()
+ */
+void CMIDItemLabel::SetWidthL(TInt aLineWidth)
+{
+ iLineWidthArray->Reset();
+ iLineWidthArray->AppendL(aLineWidth - iLabelMargins.iLeft - iLabelMargins.iRight);
+
+ WrapTextAndSetSizeL();
+}
+
+/**
+ * Wrap the text and set the size of the control to the longest line width and to the
+ * sum of the height of the lines of text.
+ */
+void CMIDItemLabel::WrapTextAndSetSizeL()
+{
+
+ iWrappedArray->Reset();
+ ResetLabelArray();
+
+ delete iWrappedText;
+ iWrappedText = NULL;
+
+ if (iMaxNumberOfLines > 0)
+ {
+ iWrappedText = HBufC::NewL(iText->Length()
+ + (iMaxNumberOfLines * KAknBidiExtraSpacePerLine));
+
+ TPtr wrappedTextPtr = iWrappedText->Des();
+ wrappedTextPtr.Append(*iText);
+
+ CArrayFixFlat<TInt>* lineWidthArray = new(ELeave) CArrayFixFlat<TInt>(iMaxNumberOfLines);
+ CleanupStack::PushL(lineWidthArray);
+
+ TInt numWidthsAvailable = iLineWidthArray->Count();
+ ASSERT(numWidthsAvailable > 0);
+
+ for (TInt i = 0; i < iMaxNumberOfLines; i++)
+ {
+ TInt width = i < numWidthsAvailable ?
+ (*iLineWidthArray)[i] :
+ (*iLineWidthArray)[numWidthsAvailable - 1];
+ lineWidthArray->AppendL(width);
+ }
+
+ AknBidiTextUtils::ConvertToVisualAndWrapToArrayL
+ (wrappedTextPtr, *lineWidthArray, *Font(), *iWrappedArray, ETrue);
+
+ CleanupStack::PopAndDestroy(lineWidthArray);
+ }
+ else if (iMaxNumberOfLines == -1)
+ { //unlimited wrapping
+ iWrappedText= AknBidiTextUtils::ConvertToVisualAndWrapToArrayWholeTextL
+ (*iText, *iLineWidthArray, *Font(), *iWrappedArray);
+ }
+
+ TInt width = 0;
+ TInt numOfLabels = iWrappedArray->Count();
+ for (TInt i=0; i < numOfLabels; i++)
+ {
+ CEikLabel* tmp = new(ELeave) CEikLabel();
+ CleanupStack::PushL(tmp);
+ tmp->UseLogicalToVisualConversion(EFalse);
+ tmp->OverrideColorL(EColorLabelText, iColor);
+ tmp->SetFont(Font());
+ tmp->SetTextL((*iWrappedArray)[i]);
+ tmp->SetSize(CMIDItemLabel::PropperEikLabelMinumumSize(*tmp));
+ tmp->EnablePictographsL(*iPictographInterface);
+ iLabelArray->AppendL(tmp);
+ CleanupStack::Pop(tmp);
+ TSize lineSize = tmp->Size();
+ width = width < lineSize.iWidth ? lineSize.iWidth : width;
+ tmp->ActivateL();
+ }
+
+ SetUnderlined(iUnderlined);
+
+ // we rely on set extent being called at some later stage to trigger SizeChanged()
+ // Label Top margin is added to label height
+
+ width += iLabelMargins.iLeft + iLabelMargins.iRight;
+ TInt height = LineHeight() * NumLines();
+ if (iIsContent)
+ {
+ // adds margin to bottom of string item content
+ height += iLabelMargins.iBottom;
+ }
+ if (iLabelBeforeContent)
+ {
+ iSize = TSize(width, height + iLabelMargins.iTop);
+ }
+ else
+ {
+ iSize = TSize(width, height + iLabelMargins.iBottom);
+ }
+}
+
+/**
+ * Prepare the line width array for the case in which the first line has
+ * a different width or the remaining lines and then call WrapTextAndSetSizeL()
+ *
+ * @see WrapTextAndSetSizeL()
+ */
+void CMIDItemLabel::SetVariableWidthL(TInt aFirstWidth, TInt aSecondWidth)
+{
+ iLineWidthArray->Reset();
+
+ iLineWidthArray->AppendL(aFirstWidth - iLabelMargins.iLeft - iLabelMargins.iRight);
+ iLineWidthArray->AppendL(aSecondWidth - iLabelMargins.iLeft - iLabelMargins.iRight);
+
+ WrapTextAndSetSizeL();
+}
+
+
+/** Returns the width in pixels of the first word */
+TInt CMIDItemLabel::FirstWordWidth() const
+{
+ if (!iText)
+ {
+ return Font()->CharWidthInPixels(KEllipsis);
+ }
+
+ TInt pos = iText->Length();
+ for (TInt i = 0; i < iText->Length(); i++)
+ {
+ if (TChar((*iText)[i]).IsSpace() || IsLineSeparator((*iText)[i]))
+ {
+ pos = i;
+ break;
+ }
+ }
+
+ return Font()->TextWidthInPixels(iText->Left(pos));
+}
+
+void CMIDItemLabel::SetCentered(TBool aValue)
+{
+ if (aValue != iCentered)
+ {
+ iCentered = aValue;
+
+ // re-layout the lables
+ SizeChanged();
+ }
+}
+
+void CMIDItemLabel::SetUnderlined(TBool aUnderlined)
+{
+ iUnderlined = aUnderlined;
+ TInt i;
+ for (i=0; i < iLabelArray->Count(); i++)
+ {
+ CEikLabel* label = (CEikLabel*)((*iLabelArray)[i]);
+ label->SetUnderlining(iUnderlined);
+ }
+}
+
+void CMIDItemLabel::SetColorL(TRgb aColor)
+{
+ iColor = aColor;
+ AknLayoutUtils::OverrideControlColorL(*this, EColorLabelText, iColor);
+ TInt i;
+ for (i=0; i < iLabelArray->Count(); i++)
+ {
+ CEikLabel* label = (CEikLabel*)((*iLabelArray)[i]);
+ label->OverrideColorL(EColorLabelText, iColor);
+ }
+}
+
+void CMIDItemLabel::SetEmphasisL(TBool aEmphasis)
+{
+ TInt i;
+ CEikLabel::TTextEmphasis emphasis = aEmphasis ?
+ CEikLabel::EPartialEmphasis :
+ CEikLabel::ENoEmphasis;
+
+ for (i=0; i < iLabelArray->Count(); i++)
+ {
+ CEikLabel* label = (CEikLabel*)((*iLabelArray)[i]);
+ label->OverrideColorL(EColorLabelHighlightPartialEmphasis, TRgb(0x32, 0x99, 0xCC));
+ label->SetEmphasis(emphasis);
+ }
+}
+
+TRgb CMIDItemLabel::GetDefaultColor()
+{
+ return iDefaultColor;
+}
+
+void CMIDItemLabel::SetFont(const MMIDFont* aFont)
+{
+ iFont = aFont;
+ PrepareFont();
+
+ for (TInt i=0; i < iLabelArray->Count(); i++)
+ {
+ CEikLabel* label = (CEikLabel*)((*iLabelArray)[i]);
+ label->SetFont(Font());
+ }
+}
+
+const CFont* CMIDItemLabel::Font() const
+{
+ return iFont ? const_cast<MMIDFont*>(iFont)->Font(ETrue) : CMIDFont::DefaultFont(iDefaultFontId);
+}
+
+CEikLabel* CMIDItemLabel::LabelAtIdx(TInt aIdx)
+{
+ if (aIdx > -1 && aIdx < iLabelArray->Count())
+ {
+ return (*iLabelArray)[aIdx];
+ }
+ return NULL;
+}
+
+void CMIDItemLabel::SetMaxWidth(TInt aMaxWidth)
+{
+ iMaxWidth = aMaxWidth;
+}
+
+CMIDItemLabel::CMIDItemLabel(TInt aMaxWidth, TBool aLabelBeforeContent, TInt aMaxNumberOfLines,
+ const CMIDFont::TDefaultId& aDefaultFontId, TBool aIsContent) :
+ iDefaultFontId(aDefaultFontId), iMaxWidth(aMaxWidth),
+ iMaxNumberOfLines(aMaxNumberOfLines), iLabelBeforeContent(aLabelBeforeContent), iIsContent(aIsContent)
+{
+}
+
+void CMIDItemLabel::ConstructL()
+{
+ iWrappedArray = new(ELeave) CArrayFixFlat<TPtrC>(2);
+ iLabelArray = new(ELeave) CArrayFixFlat<CEikLabel*>(2);
+
+ iLineWidthArray = new(ELeave) CArrayFixFlat<TInt>(2);
+
+ // Label should have proper color. This color is obtained from skin.
+ MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+ if (skin)
+ {
+ AknsUtils::GetCachedColor(skin, iDefaultColor, KAknsIIDQsnTextColors,
+ EAknsCIQsnTextColorsCG8);
+ iColor = iDefaultColor;
+ }
+
+ iPictographInterface = CAknPictographInterface::NewL(*this, *this);
+ UpdateMargins();
+ PrepareFont();
+}
+
+void CMIDItemLabel::UpdateMargins()
+{
+ TAknWindowLineLayout layout =
+ AknLayoutScalable_Avkon::form2_midp_label_pane_cp(0).LayoutLine();
+
+ iLabelMargins.iTop = layout.it;
+ iLabelMargins.iLeft = layout.il;
+ iLabelMargins.iRight = layout.ir;
+
+ // bottom margin is defined only for ImageItem, so it's read from imageitem's label pane
+ layout = AknLayoutScalable_Avkon::form2_midp_label_pane_cp(2).LayoutLine();
+
+ iLabelMargins.iBottom = layout.ib;
+
+}
+
+/**
+* Set font size for later using in labels layouting (@see SizeChanged())
+*/
+void CMIDItemLabel::PrepareFont()
+{
+ const TInt KJavaFontSmall = 16; // Java-side small font
+ const TInt KJavaFontMedium = 18; // Java-side medium font
+
+ iFontSize = 1; //if ItemLabel is label part of StringItem (or some other item which has label)
+ if (iIsContent)
+ {
+ //if ItemLabel is content part of StringItem font can have three different heights
+ //according to java side font
+ TInt fontHeight = Font()->HeightInPixels();
+ if (fontHeight <= KJavaFontSmall) // Java-side small font
+ {
+ iFontSize = 0;
+ }
+ else if (fontHeight <= KJavaFontMedium) // Java-side medium font
+ {
+ iFontSize = 1;
+ }
+ else // Java-side large font
+ {
+ iFontSize = 2;
+ }
+ }
+}
+
+void CMIDItemLabel::SizeChanged()
+{
+ TAknLayoutRect layoutRect;
+ CEikLabel* label;
+ const CAknLayoutFont* layoutFont = CAknLayoutFont::AsCAknLayoutFontOrNull(Font());
+
+ if (iIsContent) // This is a StringItem content
+ {
+ // get label rect
+ TRect rect = Rect();
+
+ // layout rect
+ layoutRect.LayoutRect(rect,
+ AknLayoutScalable_Avkon::form2_midp_string_pane(0).LayoutLine());
+ rect = layoutRect.Rect();
+
+ // determine maximum rows based on layout data available
+ TAknLayoutScalableParameterLimits textLimits =
+ AknLayoutScalable_Avkon::form2_mdip_string_pane_t1_ParamLimits(iFontSize);
+
+ TInt maxRows = textLimits.LastRow();
+
+ // layout the lines
+ TInt numOfLabels = iLabelArray->Count();
+ TAknTextLineLayout lineLayout;
+
+ for (TInt i = 0; i < numOfLabels; i++)
+ {
+ label = (*iLabelArray)[i];
+
+ if (i < maxRows)
+ {
+ // get proper layout
+ lineLayout = AknLayoutScalable_Avkon::form2_mdip_string_pane_t1(
+ iFontSize, i).LayoutLine();
+ }
+
+ // do the layouting of the label using the prepared layout
+ AknLayoutUtils::LayoutLabel(label, rect, lineLayout);
+
+ if (i > 0)
+ { // because layout function adds small gap between lines, we must
+ // set proper position
+ label->SetPosition(TPoint(label->Position().iX ,
+ (*iLabelArray)[i-1]->Position().iY + (*iLabelArray)[i-1]->Size().iHeight));
+ }
+
+ // while LayoutLabel doesn't produce the right color we have to
+ // override it with correct value
+ TRAP_IGNORE(label->OverrideColorL(EColorLabelText, iColor));
+
+ // as font in layout data is not correct for non-default fonts
+ // we need to change labels font directly
+ label->SetFont(Font());
+ //
+ label->SetSize(TSize(label->Size().iWidth, LineHeight()));
+
+ if (iCentered)
+ {
+ label->SetLabelAlignment(ELayoutAlignCenter);
+ }
+
+ } //for
+ }
+ else // This is a label
+ {
+ // get label rect
+ TRect rect = Rect();
+
+ // layout rect
+ layoutRect.LayoutRect(rect,
+ AknLayoutScalable_Avkon::form2_midp_label_pane(0).LayoutLine());
+ rect = layoutRect.Rect();
+
+ // determine maximum rows based on layout data available
+ TAknLayoutScalableParameterLimits textLimits =
+ AknLayoutScalable_Avkon::form2_midp_label_pane_t1_ParamLimits();
+
+ TInt maxRows = textLimits.LastRow();
+
+ // layout the lines
+ TInt numOfLabels = iLabelArray->Count();
+ TAknTextLineLayout lineLayout;
+
+ for (TInt i = 0; i < numOfLabels; i++)
+ {
+ label = (*iLabelArray)[i];
+
+ if (i < maxRows)
+ {
+ // get proper layout
+ lineLayout = AknLayoutScalable_Avkon::form2_midp_label_pane_t1(i, 0).LayoutLine();
+ }
+
+ // do the layouting of the label using the prepared layout
+ AknLayoutUtils::LayoutLabel(label, rect, lineLayout);
+
+ if (i > 0)
+ { // because layout function adds small gap between lines, we must
+ // set proper position
+ label->SetPosition(TPoint(label->Position().iX ,
+ (*iLabelArray)[i-1]->Position().iY + (*iLabelArray)[i-1]->Size().iHeight));
+ }
+
+ // while LayoutLabel doesn't produce the right color we have to make workaround
+ // to override it with correct value
+ TRAP_IGNORE(label->OverrideColorL(EColorLabelText, iColor));
+
+ if (iCentered)
+ {
+ label->SetLabelAlignment(ELayoutAlignCenter);
+ }
+
+ } //for
+ } //else
+}
+
+void CMIDItemLabel::ResetLabelArray()
+{
+ for (TInt i=0; i < iLabelArray->Count(); i++)
+ {
+ delete(*iLabelArray)[i];
+ }
+ iLabelArray->Reset();
+}
+
+TBool CMIDItemLabel::IsLineSeparator(const TText aChar) const
+{
+ return CMIDUtils::IsLineSeparator(aChar);
+}
+
+TSize CMIDItemLabel::PropperEikLabelMinumumSize(CEikLabel& aLabel) const
+{
+ TSize size = aLabel.MinimumSize();
+ size.iHeight = LineHeight();
+
+ if (aLabel.LogicalToVisualConversionUsed())
+ {
+ return size;
+ }
+
+ const TDesC* text = aLabel.Text();
+
+ TInt textLength = aLabel.Font()->TextWidthInPixels(*text);
+
+ // Calculate correct width, because label calculates it wrong.
+ size.iWidth = textLength + aLabel.iMargin.iLeft + aLabel.iMargin.iRight;
+
+ return size;
+}
+
+void CMIDItemLabel::DrawPictographArea()
+{
+ if (IsVisible())
+ {
+ RDrawableWindow* rDrawableWindow = DrawableWindow();
+ if (rDrawableWindow)
+ {
+ DrawDeferred();
+ }
+ }
+}
+
+void CMIDItemLabel::ResolutionChange()
+{
+ UpdateMargins();
+}
+
+TInt CMIDItemLabel::ItemLabelMargin()
+{
+ return iLabelBeforeContent ? iLabelMargins.iTop : iLabelMargins.iBottom;
+}
+
+void CMIDItemLabel::AdjustToSizeL(const TSize& aSize)
+{
+ if (iSize.iWidth != aSize.iWidth || iSize.iHeight != aSize.iHeight)
+ {
+ TInt oldNumLabelLines = iMaxNumberOfLines;
+ iMaxNumberOfLines = Min(iMaxNumberOfLines,
+ (aSize.iHeight - ItemLabelMargin()) / LineHeight());
+
+ SetWidthL(aSize.iWidth);
+ iMaxNumberOfLines = oldNumLabelLines;
+ }
+}
+
+//end of File