[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