QPlainTextEdit: draw placeholder text correctly when it wraps

382faed introduced placeholder text to QPlainTextEdit. But the code
relied on the text begin short enough to fit inside the width of
the text edit. If the text was longer, and therefore wrapped, drawing
artifacts would show.

This patch will listen for text changes and check if the
placeholder text should show or not, and if so, issue a full update
to ensure that the whole placeholder text is either fully drawn
or hidden. And then we allow to the placeholder text to be drawn
inside the full rect of the text edit.

Task-number: QTBUG-61875
Change-Id: I808472839ab397340080b56407c76e74f9ad1ae6
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Richard Moe Gustavsen 2017-07-19 12:07:17 +02:00
parent 55e273c1a2
commit 0e1c9a34c2
3 changed files with 35 additions and 11 deletions

View File

@ -747,7 +747,8 @@ QPlainTextEditPrivate::QPlainTextEditPrivate()
tabChangesFocus(false),
lineWrap(QPlainTextEdit::WidgetWidth),
wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere),
clickCausedFocus(0),topLine(0),topLineFracture(0),
clickCausedFocus(0), placeholderVisible(1),
topLine(0), topLineFracture(0),
pageUpDownLastCursorYIsValid(false)
{
showCursorOnInitialShow = true;
@ -784,6 +785,7 @@ void QPlainTextEditPrivate::init(const QString &txt)
QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged()));
QObject::connect(control, SIGNAL(textChanged()), q, SLOT(_q_textChanged()));
QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus()));
// set a null page size initially to avoid any relayouting until the textedit
@ -816,6 +818,24 @@ void QPlainTextEditPrivate::init(const QString &txt)
#endif
}
void QPlainTextEditPrivate::_q_textChanged()
{
Q_Q(QPlainTextEdit);
// We normally only repaint the part of view that contains text in the
// document that has changed (in _q_repaintContents). But the placeholder
// text is not a part of the document, but is drawn on separately. So whenever
// we either show or hide the placeholder text, we issue a full update.
bool placeholderCurrentyVisible = placeholderVisible;
placeholderVisible = !placeholderText.isEmpty()
&& q->document()->isEmpty()
&& q->firstVisibleBlock().layout()->preeditAreaText().isEmpty();
if (placeholderCurrentyVisible != placeholderVisible)
viewport->update();
}
void QPlainTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
{
Q_Q(QPlainTextEdit);
@ -1881,6 +1901,7 @@ static void fillBackground(QPainter *p, const QRectF &rect, QBrush brush, const
*/
void QPlainTextEdit::paintEvent(QPaintEvent *e)
{
Q_D(QPlainTextEdit);
QPainter painter(viewport());
Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout()));
@ -1903,6 +1924,15 @@ void QPlainTextEdit::paintEvent(QPaintEvent *e)
er.setRight(qMin(er.right(), maxX));
painter.setClipRect(er);
if (d->placeholderVisible) {
QColor col = d->control->palette().text().color();
col.setAlpha(128);
painter.setPen(col);
painter.setClipRect(e->rect());
const int margin = int(document()->documentMargin());
QRectF textRect = viewportRect.adjusted(margin, margin, 0, 0);
painter.drawText(textRect, Qt::AlignTop | Qt::TextWordWrap, placeholderText());
}
QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
@ -1977,17 +2007,8 @@ void QPlainTextEdit::paintEvent(QPaintEvent *e)
}
}
layout->draw(&painter, offset, selections, er);
if (!placeholderText().isEmpty() && document()->isEmpty() && layout->preeditAreaText().isEmpty()) {
Q_D(QPlainTextEdit);
QColor col = d->control->palette().text().color();
col.setAlpha(128);
painter.setPen(col);
const int margin = int(document()->documentMargin());
painter.drawText(r.adjusted(margin, 0, 0, 0), Qt::AlignTop | Qt::TextWordWrap, placeholderText());
} else {
layout->draw(&painter, offset, selections, er);
}
if ((drawCursor && !drawCursorAsBlock)
|| (editable && context.cursorPosition < -1
&& !layout->preeditAreaText().isEmpty())) {

View File

@ -283,6 +283,7 @@ protected:
private:
Q_DISABLE_COPY(QPlainTextEdit)
Q_PRIVATE_SLOT(d_func(), void _q_repaintContents(const QRectF &r))
Q_PRIVATE_SLOT(d_func(), void _q_textChanged())
Q_PRIVATE_SLOT(d_func(), void _q_adjustScrollbars())
Q_PRIVATE_SLOT(d_func(), void _q_verticalScrollbarActionTriggered(int))
Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged())

View File

@ -121,6 +121,7 @@ public:
void init(const QString &txt = QString());
void _q_repaintContents(const QRectF &contentsRect);
void _q_textChanged();
inline QPoint mapToContents(const QPoint &point) const
{ return QPoint(point.x() + horizontalOffset(), point.y() + verticalOffset()); }
@ -157,6 +158,7 @@ public:
uint centerOnScroll : 1;
uint inDrag : 1;
uint clickCausedFocus : 1;
uint placeholderVisible : 1;
int topLine;
qreal topLineFracture; // for non-int sized fonts