javauis/lcdui_akn/lcdui/src/CMIDItemLabel.cpp
branchRCL_3
changeset 14 04becd199f91
child 19 71c436fe3ce0
--- /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