Keep the wire numbers out of the terminal drawing

The number of a wire was written from its mark towards the terminal
without any regard for the room left: a colour code like 'gnge' ran
into the drawing of the terminal. The length of the wires setting
moves the mark, but every project has to be tuned to its longest
number by hand, and a short length leaves no room at all.

Shrink the font while the number is longer than the room between the
mark and the terminal, and clip away what still does not fit even at
the smallest size, so a number never crosses into the terminal -- the
wire length and the font stay the settings to make the drawing
pleasant, they are just no longer able to break it.

tst_cabletarget paints the strip with a long number and without any
and checks the two pictures are the same above the bottom of the
terminal: the number is drawn below it or not at all.
This commit is contained in:
Kellermorph
2026-10-19 22:22:40 +02:00
parent 29a8f018f4
commit b6312f1f78
2 changed files with 105 additions and 6 deletions
@@ -299,19 +299,45 @@ void drawCables(QPainter *painter, const QVector<CableCell> &cells, const Termin
const qreal text_height{font_metrics.height()};
//Draw a mark (small oblique line) on a wire and the number of the wire next to it.
//The text is written from the bottom to the top, at the left of the wire.
const auto draw_wire_mark = [&](qreal x, qreal mark_y, const QString &text, bool text_above)
//The text is written from the bottom to the top, at the left of the wire, starting
//above the mark and running towards the terminal: the font shrinks while the text
//is longer than the room left between the mark and the terminal, and what still
//does not fit is clipped away, so a long number never runs into the drawing of
//the terminal. The room left is @a terminal_bottom the bottom of that terminal.
const auto draw_wire_mark = [&](qreal x, qreal mark_y, qreal terminal_bottom, const QString &text)
{
painter->drawLine(QPointF{x - 3, mark_y + 3}, QPointF{x + 3, mark_y - 3});
if (text.isEmpty()) {
return;
}
const qreal text_width{font_metrics.horizontalAdvance(text)};
//Room left between the mark and the terminal
const qreal room{mark_y - 4 - (terminal_bottom + 2)};
if (room <= 0) {
return;
}
QFont text_font{painter->font()};
if (text_font.pixelSize() <= 0 && text_font.pointSizeF() > 0) {
text_font.setPixelSize(qMax(4, qRound(text_font.pointSizeF() * 96.0 / 72.0)));
}
while (QFontMetricsF{text_font}.horizontalAdvance(text) > room &&
text_font.pixelSize() > 4) {
text_font.setPixelSize(text_font.pixelSize() - 1);
}
const QFontMetricsF fitted_metrics{text_font};
const qreal fitted_width{fitted_metrics.horizontalAdvance(text)};
const qreal fitted_height{fitted_metrics.height()};
painter->save();
painter->translate(x - 1, text_above ? mark_y - 4 : mark_y + 4 + text_width);
painter->setFont(text_font);
//The clip keeps the text under the terminal even when a number is
//so long that the smallest font does not fit it any more
painter->setClipRect(QRectF{x - 1 - fitted_height, terminal_bottom + 2,
fitted_height + 1, room});
painter->translate(x - 1, mark_y - 4);
painter->rotate(270);
painter->drawText(QRectF{0, -text_height, text_width + 2, text_height},
painter->drawText(QRectF{0, -fitted_height, fitted_width + 2, fitted_height},
Qt::AlignLeft | Qt::AlignVCenter,
text);
painter->restore();
@@ -359,7 +385,7 @@ void drawCables(QPainter *painter, const QVector<CableCell> &cells, const Termin
for (const auto &wire : std::as_const(wires))
{
painter->drawLine(QPointF{wire.x, wire.bottom}, QPointF{wire.x, bar_1_y});
draw_wire_mark(wire.x, qMax(wire.bottom + 4, bar_1_y - 10), wire.wire, true);
draw_wire_mark(wire.x, qMax(wire.bottom + 4, bar_1_y - 10), wire.bottom, wire.wire);
}
painter->drawLine(QPointF{min_x, bar_1_y}, QPointF{max_x, bar_1_y});