Scale curly and double underlines with font size

Curly underlines are implemented by drawing two parallel, complementary-dashed
lines with a distance of 2 pixels.

This means they dont' scale with font size. They only look good with a small
font size. At a first glance, they are also not so easy to tell apart from
regular underlines.

Fix this by
1. drawing a cosine wave instead of of parallel dashed lines
2. always drawing a full wave period per glph, indendent of the font size
3. using the text line width, instead of always using 1px

A similar (but much less prominent) issue exists for double underlines.
Change them too, keeping the implementation consistent.

Tested with

    printf '\033[31m\033[4:3mcurly\033[4m\033[31m\033[4:2mdouble\033[4m'

Note that the curly underline overlaps with the "y".  Perhaps we should
fix this.

Probably there are more improvements to be made, and it's possible there is
a more elegant solution than repeated drawArc() calls.

Publishing this early nevertheless because it's hopefully close to an overall
improvement; But I did not have a chance to look into the bugs mentioned in
76f879cd7 (Draw characters in exact positions, 2022-08-06)
This commit is contained in:
Johannes Altmanninger
2025-05-05 12:50:52 +02:00
committed by Christoph Cullmann
parent 7c7670d0d3
commit 5ab23a964f

View File

@@ -901,7 +901,6 @@ void TerminalPainter::drawAboveText(QPainter &painter,
+ m_parentDisplay->terminalFont()->lineSpacing() / static_cast<qreal>(2);
if (underline == RE_UNDERLINE_DOUBLE || underline == RE_UNDERLINE_CURL) {
y = rect.bottom() - 1;
lw = 1;
}
pen.setWidth(lw);
if (underline == RE_UNDERLINE_DOT) {
@@ -909,19 +908,33 @@ void TerminalPainter::drawAboveText(QPainter &painter,
} else if (underline == RE_UNDERLINE_DASH) {
pen.setStyle(Qt::DashLine);
}
if (underline == RE_UNDERLINE_CURL) {
QVector<qreal> dashes(2, 2);
pen.setDashPattern(dashes);
}
painter.setPen(pen);
const int x1 = rect.x() + fontWidth * startUnderline;
const int x2 = rect.x() + fontWidth * i - 1;
painter.drawLine(QLineF(x1, y, x2, y));
if (underline == RE_UNDERLINE_DOUBLE) {
painter.drawLine(x1, y - 2, x2, y - 2);
}
if (underline == RE_UNDERLINE_CURL) {
painter.drawLine(QLineF(x1 + 2, y - 1, x2, y - 1));
if (underline != RE_UNDERLINE_CURL)
painter.drawLine(QLineF(x1, y, x2, y));
if (underline == RE_UNDERLINE_DOUBLE || underline == RE_UNDERLINE_CURL) {
const int fontHeight = m_parentDisplay->terminalFont()->fontHeight();
const int amplitude = fontHeight / 8;
if (underline == RE_UNDERLINE_DOUBLE) {
if (amplitude)
painter.drawLine(x1, y - amplitude, x2, y - amplitude);
} else {
y = std::max(static_cast<qreal>(0), y - amplitude);
assert(underline == RE_UNDERLINE_CURL);
const int len = x2 - x1;
if (len > 0) {
const int halfPeriodsPerGlyph = 2;
const int numHalfPeriods = len * halfPeriodsPerGlyph / fontWidth;
for (int j = 0; j < numHalfPeriods; j++) {
const int begin = j * len / numHalfPeriods;
const int end = (j + 1) * len / numHalfPeriods;
const qreal angle1 = 0.0;
const qreal angle2 = 360.0 * 16.0 * ((j % 2 == 0) ? 0.5 : -0.5);
painter.drawArc(x1 + begin, y, end-begin, amplitude, angle1, angle2);
}
}
}
}
startUnderline = -1;