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:
parent
55e273c1a2
commit
0e1c9a34c2
@ -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())) {
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user