Skip to content

Commit

Permalink
wiggly example: add support for emojis etc. (utf16 surrogate pairs)
Browse files Browse the repository at this point in the history
The venerable wiggly example was created before unicode support was
added to Qt. Hence, when extracting the individual characters from the
string for painting, the code was not prepared to handle that some
characters, like emojis, are composed of two QChar elements.

Fixes: QTBUG-28853
Change-Id: I9804415f92775e2b78fa9fcaf7a2d112153cdce0
Reviewed-by: Eskil Abrahamsen Blomfeldt <[email protected]>
  • Loading branch information
aavit committed Dec 12, 2022
1 parent 6a3627b commit 4a5abfc
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 11 deletions.
13 changes: 8 additions & 5 deletions examples/widgets/doc/src/wiggly.qdoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
{QLineEdit::textChanged()}{textChanged()} signal to the wiggly
widget's \c setText() slot to obtain the real time interaction
with the wiggly widget. The widget's default text is "Hello
world!".
world!", with an emoji thrown in for fun.

\section1 WigglyWidget Class Definition

Expand Down Expand Up @@ -115,13 +115,16 @@

Each time the \c paintEvent() function is called, we create a
QPainter object \c painter to draw the contents of the widget.
For each character in \c text, we determine the color and the
position on the wiggly line based on \c step. In addition, \c x
is incremented by the character's width.
Since we are going to paint the character symbols individually, we
extract the unique unicode code point for each character from \c
text, and convert it to a string \c symbol. For each \c symbol, we
determine the color and the position on the wiggly line based on
\c step and its \c offset from the start of the text. In addition,
\c x is incremented by the symbol's width.

For simplicity, we assume that QFontMetrics::horizontalAdvance(\c text)
returns the sum of the individual character advances
(QFontMetrics::horizontalAdvance(\c text[i])). In practice, this is not
(QFontMetrics::horizontalAdvance(\c symbol)). In practice, this is not
always the case because QFontMetrics::horizontalAdvance(\c text) also takes
into account the kerning between certain letters (e.g., 'A' and
'V'). The result is that the text isn't perfectly centered. You
Expand Down
2 changes: 1 addition & 1 deletion examples/widgets/widgets/wiggly/dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Dialog::Dialog(QWidget *parent)
layout->addWidget(lineEdit);

connect(lineEdit, &QLineEdit::textChanged, wigglyWidget, &WigglyWidget::setText);
lineEdit->setText(tr("Hello world!"));
lineEdit->setText(u8"🖖 " + tr("Hello world!"));

setWindowTitle(tr("Wiggly"));
resize(360, 145);
Expand Down
11 changes: 6 additions & 5 deletions examples/widgets/widgets/wiggly/wigglywidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ void WigglyWidget::paintEvent(QPaintEvent * /* event */)
//! [3]
QPainter painter(this);
//! [3] //! [4]
for (int i = 0; i < text.size(); ++i) {
int index = (step + i) % 16;
int offset = 0;
for (char32_t codePoint : text.toUcs4()) {
int index = (step + offset++) % 16;
color.setHsv((15 - index) * 16, 255, 191);
painter.setPen(color);
painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400),
QString(text[i]));
x += metrics.horizontalAdvance(text[i]);
QString symbol = QString::fromUcs4(&codePoint, 1);
painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400), symbol);
x += metrics.horizontalAdvance(symbol);
}
}
//! [4]
Expand Down

0 comments on commit 4a5abfc

Please sign in to comment.