[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    KDE/kdebase/workspace/plasma/applets/tasks
From:       Fredrik Höglund <fredrik () kde ! org>
Date:       2007-10-22 1:33:20
Message-ID: 1193016800.443656.18846.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 727891 by fredrik:

Refactor the task button text layout and rendering code to handle text
that won't fit in the available space better.

* Elide lines that won't fit by fading the text out at the end.
* Don't extend the button labels above and below the buttons when there
  are more lines than will fit.
* Handle reversed layout correctly within the buttons.


 M  +125 -16   tasks.cpp  
 M  +20 -0     tasks.h  


--- trunk/KDE/kdebase/workspace/plasma/applets/tasks/tasks.cpp #727890:727891
@@ -23,6 +23,7 @@
 
 // Standard
 #include <math.h>
+#include <limits.h>
 
 // Qt
 #include <QApplication>
@@ -33,6 +34,8 @@
 #include <QTimeLine>
 #include <QStyleOptionGraphicsItem>
 #include <QtDebug>
+#include <QTextLayout>
+#include <QTextOption>
 
 // KDE
 #include <KAuthorized>
@@ -313,28 +316,129 @@
     }
 }
 
-QRectF AbstractTaskItem::iconRect() const
+QSize AbstractTaskItem::layoutText(QTextLayout &layout, const QString &text,
+                                   const QSize &constraints) const
 {
-    QSizeF iconSize = _icon.actualSize(boundingRect().size().toSize());
-    //iconSize.scale(boundingRect().size(),Qt::KeepAspectRatio);
+    QFontMetrics metrics(layout.font());
+    int leading     = metrics.leading();
+    int height      = 0;
+    int maxWidth    = constraints.width();
+    int widthUsed   = 0;
+    int lineSpacing = metrics.lineSpacing();
+    QTextLine line;
 
-    QRectF rect = QRectF(QPointF(0,0), iconSize);
-    rect.moveTop((boundingRect().height() - rect.height()) / 2);
+    layout.setText(text);
 
-    return rect;
+    layout.beginLayout();
+    while ((line = layout.createLine()).isValid())
+    {
+        height += leading;
+
+        // Make the last line that will fit infinitely long.
+        // drawTextLayout() will handle this by fading the line out
+        // if it won't fit in the contraints.
+        if (height + 2 * lineSpacing > constraints.height())
+            maxWidth = INT_MAX;
+
+        line.setLineWidth(maxWidth);
+        line.setPosition(QPoint(0, height));
+
+        height += int(line.height());
+        widthUsed = int(qMax(qreal(widthUsed), line.naturalTextWidth()));
+    }
+    layout.endLayout();
+
+    return QSize(widthUsed, height);
 }
 
-QRectF AbstractTaskItem::textRect() const
+void AbstractTaskItem::drawTextLayout(QPainter *painter, const QTextLayout &layout, \
const QRect &rect) const  {
-    QRectF text = boundingRect();
-    text.setLeft(iconRect().right() + IconTextSpacing);
+    QPixmap pixmap(rect.size());
+    pixmap.fill(Qt::transparent);
 
-    text.setTop(text.top() + 5);
-    text.setBottom(text.bottom() - 5);
+    QPainter p(&pixmap);
+    p.setPen(painter->pen());
 
-    return text;
+    // Create the alpha gradient for the fade out effect
+    QLinearGradient alphaGradient(0, 0, 1, 0);
+    alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
+    if (layout.textOption().textDirection() == Qt::LeftToRight)
+    {
+        alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
+        alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
+    } else
+    {
+        alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
+        alphaGradient.setColorAt(1, QColor(0, 0, 0, 255));
+    }
+
+    QFontMetrics fm(layout.font());
+    int textHeight = layout.lineCount() * fm.lineSpacing();
+    QPointF position = textHeight < rect.height() ?
+            QPointF(0, (rect.height() - textHeight) / 2) : QPointF(0, 0);
+    QList<QRect> fadeRects;
+    int fadeWidth = 30;
+
+    // Draw each line in the layout
+    for (int i = 0; i < layout.lineCount(); i++)
+    {
+        QTextLine line = layout.lineAt(i);
+        line.draw(&p, position);
+
+        // Add a fade out rect to the list if the line is too long
+        if (line.naturalTextWidth() > rect.width())
+        {
+            int x = int(qMin(line.naturalTextWidth(), (qreal)pixmap.width())) - \
fadeWidth; +            int y = int(line.position().y() + position.y());
+            QRect r = QStyle::visualRect(layout.textOption().textDirection(), \
pixmap.rect(), +                                         QRect(x, y, fadeWidth, \
int(line.height()))); +            fadeRects.append(r);
+        }
+    }
+
+    // Reduce the alpha in each fade out rect using the alpha gradient
+    if (!fadeRects.isEmpty())
+    {
+        p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+        foreach (const QRect &rect, fadeRects)
+            p.fillRect(rect, alphaGradient);
+    }
+
+    p.end();
+
+    painter->drawPixmap(rect.topLeft(), pixmap);
 }
 
+QTextOption AbstractTaskItem::textOption() const
+{
+    Qt::LayoutDirection direction = QApplication::layoutDirection();
+    Qt::Alignment alignment = QStyle::visualAlignment(direction, Qt::AlignLeft | \
Qt::AlignVCenter); +
+    QTextOption option;
+    option.setTextDirection(direction);
+    option.setAlignment(alignment);
+    option.setWrapMode(QTextOption::WordWrap);
+
+    return option;
+}
+
+QRectF AbstractTaskItem::iconRect() const
+{
+    QSize iconSize = _icon.actualSize(boundingRect().size().toSize());
+
+    return QStyle::alignedRect(QApplication::layoutDirection(), Qt::AlignLeft | \
Qt::AlignVCenter, +                               iconSize, boundingRect().toRect());
+}
+
+QRectF AbstractTaskItem::textRect() const
+{
+    QSize size(boundingRect().size().toSize());
+    size.rwidth() -= int(iconRect().width()) + qMin(0, IconTextSpacing - 2);
+
+    return QStyle::alignedRect(QApplication::layoutDirection(), Qt::AlignRight | \
Qt::AlignVCenter, +                                     size, \
boundingRect().toRect()); +}
+
 void AbstractTaskItem::drawTask(QPainter *painter,
                                 const QStyleOptionGraphicsItem *option,
                                 QWidget *)
@@ -353,10 +457,15 @@
     // FIXME HARDCODE testing
     painter->setPen(QPen(QColor(200,200,200), 1.0));
 
-    painter->setBrush(QBrush());
-    painter->drawText(textRect(),
-                      Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap,
-                      _text);
+    QRect rect = textRect().toRect();
+    rect.adjust(2, 2, -2, -2); // Create a text margin
+
+    QTextLayout layout;
+    layout.setFont(painter->font());
+    layout.setTextOption(textOption());
+
+    layoutText(layout, _text, rect.size());
+    drawTextLayout(painter, layout, rect);
 }
 
 void AbstractTaskItem::paint(QPainter *painter,
--- trunk/KDE/kdebase/workspace/plasma/applets/tasks/tasks.h #727890:727891
@@ -31,6 +31,8 @@
 
 class QGraphicsSceneDragDropEvent;
 class QTimeLine;
+class QTextLayout;
+class QTextOption;
 
 class AbstractTaskItem;
 class AbstractGroupingStrategy;
@@ -222,7 +224,25 @@
                           const QStyleOptionGraphicsItem *option,
                           QWidget *widget);
 
+    /** Returns a QTextOption object for the icon label QTtextLayout.*/
+    QTextOption textOption() const;
 
+    /**
+     * Lays the text out in the text layout using the constraints, and returns the \
actual +     * size required. The returned size may be wider than the constraints if \
the text +     * contains a non-breakable word that is wider than the maximum width.
+     * If more height is needed than what's available, the last line that will fit \
will be +     * extended to hold the remainder of the text.
+     */
+    QSize layoutText(QTextLayout &layout, const QString &text, const QSize \
&constraints) const; +
+    /**
+     * Draws the text layout (which must already have the text layed out) in the \
rect using +     * the supplied painter. If the layout contains text lines that are \
longer than the rect +     * is wide, they will be elided by fading the text out.
+     */
+    void drawTextLayout(QPainter *painter, const QTextLayout &layout, const QRect \
&rect) const; +
 private slots:
     void animationUpdate();
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic