src/hbcore/primitives/hbtextitem.cpp
changeset 3 11d3954df52a
parent 1 f7ac710697a9
child 6 c3690ec91ef8
--- a/src/hbcore/primitives/hbtextitem.cpp	Fri May 14 16:09:54 2010 +0300
+++ b/src/hbcore/primitives/hbtextitem.cpp	Thu May 27 13:10:59 2010 +0300
@@ -53,8 +53,6 @@
 HbTextItemPrivate::HbTextItemPrivate () :
     mAlignment(Qt::AlignLeft | Qt::AlignVCenter),
     mElideMode(Qt::ElideNone),
-    mDontPrint(false),
-    mDontClip(false),
     mInvalidateShownText(true),
     mOffsetPos(0,0),
     mPaintFaded(false),
@@ -73,7 +71,7 @@
     Q_Q(HbTextItem);
 
     q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-    q->setFlag(QGraphicsItem::ItemClipsToShape, !mDontClip);
+    q->setFlag(QGraphicsItem::ItemClipsToShape, false);
     q->setFlag(QGraphicsItem::ItemIsSelectable, false);
     q->setFlag(QGraphicsItem::ItemIsFocusable,  false);
 
@@ -272,8 +270,12 @@
         break;
     }
 
-    if(mDontClip)  flags |= Qt::TextDontClip;
-    if(mDontPrint) flags |= Qt::TextDontPrint;
+    if(q_ptr->flags().testFlag(QGraphicsItem::ItemClipsToShape)) {
+        flags |= Qt::TextDontClip;
+    }
+    if(!q_ptr->isVisible()) { // or ItemHasNoContents?
+        flags |= Qt::TextDontPrint;
+    }
 
     return flags;
 }
@@ -418,96 +420,102 @@
 }
 
 /*
-    This method paint each line in tree pieces.
-    In each piece uses different pen.
-    When fade effect is not needed on some end centerPen is used.
+    This method paints single piece of text layout.
+    If line contains criticalX value then fadePen is used for painting in other
+    case normalPen is used.
  */
-int HbTextItemPrivate::paintFaded(QPainter *painter,
+void HbTextItemPrivate::paintArea(QPainter *painter,
                                   int firstItemToPaint,
-                                  const QPen& leftPen,
-                                  const QPen& centerPen,
-                                  const QPen& rightPen,
-                                  const QRectF& area ) const
+                                  int lastItemToPaint,
+                                  const QPen& normalPen,
+                                  const QPen& fadePen,
+                                  qreal criticalX) const
 {
-    Q_Q(const HbTextItem);
-
-    const int n = mTextLayout.lineCount();
-    const qreal leftBorder = q->contentsRect().left()-KFadeTolerance;
-    const qreal rightBorder = q->contentsRect().right()+KFadeTolerance;
-
-    QRectF leftRect(area);
-    leftRect.setRight(mFadeFromRect.left());
-    QRectF centerRect(area);
-    centerRect.moveLeft(leftRect.right());
-    centerRect.setRight(mFadeFromRect.right());
-    QRectF rightRect(area);
-    rightRect.setLeft(centerRect.right());
-
-    qreal maxY = area.bottom();
-
-    for(int i=firstItemToPaint; i<n; ++i) {
+    for(int i=firstItemToPaint; i<=lastItemToPaint; ++i) {
         QTextLine line = mTextLayout.lineAt(i);
         QRectF lineRect = line.naturalTextRect();
         lineRect.translate(mOffsetPos);
 
 #ifdef HB_FADE_EFFECT_WORKAROUND_ON_PHONE
-        const QPointF gradientOffset(
-                QPointF(lineRect.left(),
-                        lineRect.top()+line.ascent())
-                );
+        const QPointF gradientOffset(lineRect.left(),
+                                     lineRect.top()+line.ascent());
+
+        if (lineRect.left()<criticalX && lineRect.right()>criticalX) {
+            setPainterPen(painter, fadePen, gradientOffset);
+        } else {
+            setPainterPen(painter, normalPen, gradientOffset);
+        }
+#else
+        if (lineRect.left()<criticalX && lineRect.right()>criticalX) {
+            painter->setPen(fadePen);
+        } else {
+            painter->setPen(normalPen);
+        }
 #endif // HB_FADE_EFFECT_WORKAROUND_ON_PHONE
 
-        QRectF currentCenter(centerRect);
-
-        if(lineRect.top()>maxY) {
-            // stop painting line by line
-            return i; // current line won't be painted at all
-        }
+        line.draw(painter, mOffsetPos);
+    } // for i
+}
 
-        if(lineRect.left()<leftBorder) {
-#ifdef HB_FADE_EFFECT_WORKAROUND_ON_PHONE
-            setPainterPen(painter, leftPen, gradientOffset);
-#else
-            painter->setPen(leftPen);
-#endif
-            painter->setClipRect(leftRect);
-            line.draw(painter, mOffsetPos);
-        } else {
-            // no fade on this end so extend currentCenter
-            currentCenter.setLeft(leftRect.left());
-        }
+/*
+    This method is used to draw center part of lines.
+    It is also used to calculate range of lines needed for painting in this range.
+ */
+int HbTextItemPrivate::paintArea(QPainter *painter,
+              int firstItemToPaint,
+              const QPen& normalPen,
+              qreal lastValidY) const
+{
+    int i;
+    const int n = mTextLayout.lineCount();
 
-        if(lineRect.right()>rightBorder) {
-#ifdef HB_FADE_EFFECT_WORKAROUND_ON_PHONE
-            setPainterPen(painter, rightPen, gradientOffset);
-#else
-            painter->setPen(rightPen);
+#ifndef HB_FADE_EFFECT_WORKAROUND_ON_PHONE
+    painter->setPen(normalPen);
 #endif
-            painter->setClipRect(rightRect);
-            line.draw(painter, mOffsetPos);
-        } else {
-            // no fade on this end so extend currentCenter
-            currentCenter.setRight(rightRect.right());
+
+    for(i=firstItemToPaint; i<n; ++i) {
+        QTextLine line = mTextLayout.lineAt(i);
+        QRectF lineRect = line.naturalTextRect();
+        lineRect.translate(mOffsetPos);
+
+        if (lineRect.top()>lastValidY) {
+            return i;
         }
-
-        if(currentCenter.width()>0) {
 #ifdef HB_FADE_EFFECT_WORKAROUND_ON_PHONE
-            setPainterPen(painter, centerPen, gradientOffset);
-#else
-            painter->setPen(centerPen);
-#endif
-            painter->setClipRect(currentCenter);
-            line.draw(painter, mOffsetPos);
+        const QPointF gradientOffset(lineRect.left(),
+                                     lineRect.top()+line.ascent());
+
+        setPainterPen(painter, normalPen, gradientOffset);
+#endif // HB_FADE_EFFECT_WORKAROUND_ON_PHONE
+
+        line.draw(painter, mOffsetPos);
+
+        if (lineRect.bottom()>lastValidY) {
+            return i;
         }
+    } // for i
+    return n-1;
+}
 
-        if(lineRect.bottom()>maxY) {
-            // stop painting line by line
-            return i; // current line has been painted partially
+bool HbTextItemPrivate::setClipPath(QPainter *painter,
+                                    const QRectF& rect,
+                                    const QPainterPath& initialCliping) const
+{
+    if (initialCliping.isEmpty()) {
+        painter->setClipRect(rect);
+    } else {
+        QPainterPath newPath(rect.topLeft());
+        newPath.addRect(rect);
+
+        if (!initialCliping.intersects(newPath)) {
+            return false; // dont paint
         }
-    } // for loop
+        newPath = initialCliping.intersected(newPath);
 
-    return n;
-} // paintFaded()
+        painter->setClipPath(newPath);
+    }
+    return true;
+}
 
 void HbTextItemPrivate::paintWithFadeEffect(QPainter *painter) const
 {
@@ -515,6 +523,7 @@
 
     QLinearGradient gradient;
     setupGradient(&gradient, q->textColor());
+    const QPainterPath initialClipPath = painter->clipPath();
 
     const QRectF contentRect = q->contentsRect();
     int i=0;
@@ -534,19 +543,32 @@
     if(mTextLayout.lineAt(0).y()+mOffsetPos.y()<contentRect.top()) {
         centerRect.setTop(mFadeFromRect.top());
 
-        // top left gradient (//):
+        // top center gradient (==):
         QPointF from(mFadeFromRect.topLeft());
+        gradient.setStart(mFadeFromRect.left(),mFadeToRect.top());
+        gradient.setFinalStop(from);
+        QBrush centerBrush(gradient);
+        QPen centerPen;
+        centerPen.setBrush(centerBrush);
+
+        if (setClipPath(painter,
+                        QRectF(gradient.start(), mFadeFromRect.topRight()),
+                        initialClipPath)) {
+            i = paintArea(painter, 0, centerPen, from.y());
+        } else {
+            i = 0;
+        }
+
+        // top left gradient (//):
         gradient.setStart(from.x()-mCornerFadeX, from.y()-mCornerFadeY);
-        gradient.setFinalStop(from);
         QBrush leftBrush(gradient);
         QPen leftPen;
         leftPen.setBrush(leftBrush);
-
-        // top center gradient (==):
-        gradient.setStart(mFadeFromRect.left(),mFadeToRect.top());
-        QBrush centerBrush(gradient);
-        QPen centerPen;
-        centerPen.setBrush(centerBrush);
+        if (setClipPath(painter,
+                        QRectF(mFadeToRect.topLeft(), mFadeFromRect.topLeft()),
+                        initialClipPath)) {
+            paintArea(painter, 0, i, centerPen, leftPen, contentRect.left()-KFadeTolerance);
+        }
 
         // top right gradient (\\):
         from = mFadeFromRect.topRight();
@@ -556,52 +578,94 @@
         QPen rightPen;
         rightPen.setBrush(rightBrush);
 
-        QRectF clipTo(mFadeToRect);
-        clipTo.setBottom(mFadeFromRect.top());
-        i = paintFaded(painter, 0, leftPen, centerPen, rightPen, clipTo);
+        if (setClipPath(painter,
+                        QRectF(mFadeToRect.topRight(), mFadeFromRect.topRight()),
+                        initialClipPath)) {
+            paintArea(painter, 0, i, centerPen, rightPen, contentRect.right()+KFadeTolerance);
+        }
     }
 
+    bool paintBottom = false;
     if(mTextLayout.lineAt(n-1).naturalTextRect().bottom()+mOffsetPos.y()>contentRect.bottom()) {
         // bottom fade is needed here
         centerRect.setBottom(mFadeFromRect.bottom());
+        paintBottom = true;
     }
 
     // paint center part
     {
+        int startFrom = i;
+        QPen centerPen(q->textColor());
+        if (setClipPath(painter,
+                        QRectF(QPointF(mFadeFromRect.left(), centerRect.top()),
+                               QPointF(mFadeFromRect.right(), centerRect.bottom())),
+                        initialClipPath)) {
+            // center with no gradient:
+            i = paintArea(painter, i, centerPen, centerRect.bottom());
+        }
+
         // left gradient | ||
         gradient.setStart(mFadeToRect.left(), mFadeFromRect.top());
         gradient.setFinalStop(mFadeFromRect.topLeft());
         QBrush leftBrush(gradient);
         QPen leftPen;
         leftPen.setBrush(leftBrush);
+        if (setClipPath(painter,
+                        QRectF(centerRect.topLeft(),
+                               QPointF(mFadeFromRect.left(),
+                                       centerRect.bottom())),
+                        initialClipPath)) {
+            paintArea(painter, startFrom, i, centerPen, leftPen, contentRect.left()-KFadeTolerance);
+        }
 
-        // center with no gradient:
-        QPen centerPen(q->textColor());
-
-        // top right gradient || |
+        // right gradient || |
         gradient.setStart(mFadeToRect.right(), mFadeFromRect.top());
         gradient.setFinalStop(mFadeFromRect.topRight());
         QBrush rightBrush(gradient);
         QPen rightPen;
         rightPen.setBrush(rightBrush);
-        i = paintFaded(painter, i, leftPen, centerPen, rightPen, centerRect);
+
+        if (setClipPath(painter,
+                        QRectF(QPointF(mFadeFromRect.right(), centerRect.top()),
+                               centerRect.bottomRight()),
+                        initialClipPath)) {
+            paintArea(painter, startFrom, i, centerPen, rightPen, contentRect.right()+KFadeTolerance);
+        }
     }
 
     // need to draw bottom as faded? is some lines remained?
-    if(i<n) {
-        // bottom left gradient (\\):
+    if (paintBottom) {
+        int startFrom = i;
+
+        // bottom center gradient (==):
         QPointF from(mFadeFromRect.bottomLeft());
+        gradient.setFinalStop(from);
+        gradient.setStart(mFadeFromRect.left(),mFadeToRect.bottom());
+        QBrush centerBrush(gradient);
+        QPen centerPen;
+        centerPen.setBrush(centerBrush);
+
+        if (setClipPath(painter,
+                        QRectF(mFadeFromRect.bottomLeft(),
+                               QPointF(mFadeFromRect.right(), mFadeToRect.bottom())),
+                        initialClipPath)) {
+            // center with no gradient:
+            i = paintArea(painter, i, centerPen, mFadeToRect.bottom());
+        }
+
+        // bottom left gradient (\\):
         gradient.setStart(from.x()-mCornerFadeX, from.y()+mCornerFadeY);
-        gradient.setFinalStop(from);
         QBrush leftBrush(gradient);
         QPen leftPen;
         leftPen.setBrush(leftBrush);
 
-        // bottom center gradient (==):
-        gradient.setStart(mFadeFromRect.left(),mFadeToRect.bottom());
-        QBrush centerBrush(gradient);
-        QPen centerPen;
-        centerPen.setBrush(centerBrush);
+        if (setClipPath(painter,
+                        QRectF(mFadeFromRect.bottomLeft(),
+                               mFadeToRect.bottomLeft()),
+                        initialClipPath)) {
+            // center with no gradient:
+            paintArea(painter, startFrom, i, centerPen, leftPen, contentRect.left()-KFadeTolerance);
+        }
 
         // bottom right gradient (//):
         from = mFadeFromRect.bottomRight();
@@ -611,10 +675,17 @@
         QPen rightPen;
         rightPen.setBrush(rightBrush);
 
-        QRectF clipTo(mFadeToRect);
-        clipTo.setTop(mFadeFromRect.bottom());
-        i = paintFaded(painter, 0, leftPen, centerPen, rightPen, clipTo);
+        if (setClipPath(painter,
+                        QRectF(mFadeFromRect.bottomRight(),
+                               mFadeToRect.bottomRight()),
+                        initialClipPath)) {
+            // center with no gradient:
+            paintArea(painter, startFrom, i, centerPen, rightPen, contentRect.right()+KFadeTolerance);
+        }
     }
+
+    // restoring initial clipping region
+    painter->setClipPath(initialClipPath);
 }
 
 void HbTextItemPrivate::setFadeLengths(qreal xLength, qreal yLength)
@@ -654,7 +725,7 @@
 QRectF HbTextItemPrivate::boundingRect (const QRectF& contentsRect) const
 {
     QRectF result(layoutBoundingRect());
-    if(!mDontClip) {
+    if(q_ptr->flags().testFlag(QGraphicsItem::ItemClipsToShape)) {
         // clip
         QRectF clippedTo = contentsRect;
 
@@ -898,6 +969,11 @@
     Q_UNUSED(option);
     Q_UNUSED(widget);
 
+    // optimalization:
+    if (option->exposedRect.isEmpty()) {
+        return;
+    }
+
     // Save painter's state
     QPen oldPen = painter->pen();
 
@@ -910,20 +986,20 @@
         painter->drawRect(rect);
     }
 
-    if(!d->mDontPrint) {
-        painter->setPen(textColor());
+
+    painter->setPen(textColor());
 
-        Q_ASSERT(d->mPaintFaded == d->fadeNeeded(contentsRect()));
-        if(!d->mDontClip && d->mPaintFaded ) {
-            d->paintWithFadeEffect(painter);
-        } else {
-            d->mTextLayout.draw(painter,
-                                d->mOffsetPos,
-                                QVector<QTextLayout::FormatRange>(),
-                                d->mDontClip?QRectF():contentsRect());
-        }
+    Q_ASSERT(d->mPaintFaded == d->fadeNeeded(contentsRect()));
+    if(d->mPaintFaded ) {
+        d->paintWithFadeEffect(painter);
+    } else {
+        d->mTextLayout.draw(painter,
+                            d->mOffsetPos,
+                            QVector<QTextLayout::FormatRange>(),
+                            flags().testFlag(ItemClipsToShape)?contentsRect():QRectF());
     }
 
+
     // Restore painter's state
     painter->setPen(oldPen);
 }
@@ -1153,53 +1229,46 @@
     Shows (default) or hides text.
     Size hint remains unchanged (same as when text is visible).
 
-    \sa HbTextItem::isVisible()
+    Equvalent of QGraphicsItem::setVisible(bool)
  */
 void HbTextItem::setTextVisible(bool isVisible)
 {
-    Q_D(HbTextItem);
-    if( d->mDontPrint == isVisible ) {
-        d->mDontPrint = !isVisible;
-        update();
-    }
+    setVisible(isVisible);
 }
 
 /*!
     Returns if text is visible.
 
     \sa HbTextItem::setTextVisible(bool)
+
+    Equvalent of QGraphicsItem::isVisible()
  */
 bool HbTextItem::isTextVisible() const
 {
-    Q_D(const HbTextItem);
-    return !d->mDontPrint;
+    return isVisible();
 }
 
 /*!
-    enables (default) or disables text clipping when item geometry is too small.
+    enables (default) od disables text cliping when item geometry is to small.
 
     \sa HbTextItem::isTextClip()
+
+    Equvalent of QGraphicsItem::setFlag(QGraphicsItem::ItemClipsToShape, clipping)
  */
 void HbTextItem::setTextClip(bool clipping)
 {
-    Q_D(HbTextItem);
-    if( d->mDontClip == clipping ) {
-        prepareGeometryChange();
-        d->mDontClip = !clipping;
-        setFlag(QGraphicsItem::ItemClipsToShape, clipping);
-        update();
-    }
+    setFlag(QGraphicsItem::ItemClipsToShape, clipping);
 }
 
 /*!
-    Returns true if text is clipped when item geometry is too small.
+    Returns true if text is cliped when item geometry is to small.
+    \sa HbTextItem::setTextClip(bool)
 
-    \sa HbTextItem::setTextClip(bool)
+    Equvalent of QGraphicsItem::flags().testFlag(QGraphicsItem::ItemClipsToShape)
  */
 bool HbTextItem::isTextClip() const
 {
-    Q_D(const HbTextItem);
-    return !d->mDontClip;
+    return flags().testFlag(ItemClipsToShape);
 }
 
 /*!