From b6312f1f78ec0ffaf640d8adc3831cdacd349285 Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Mon, 19 Oct 2026 22:22:40 +0200 Subject: [PATCH] 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. --- .../GraphicsItem/terminalstripdrawer.cpp | 38 ++++++++-- tests/qttest/tst_cabletarget.cpp | 73 +++++++++++++++++++ 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp b/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp index 282729d30..fc343ac7c 100644 --- a/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp +++ b/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp @@ -299,19 +299,45 @@ void drawCables(QPainter *painter, const QVector &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 &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}); diff --git a/tests/qttest/tst_cabletarget.cpp b/tests/qttest/tst_cabletarget.cpp index b87385aca..1ca83a347 100644 --- a/tests/qttest/tst_cabletarget.cpp +++ b/tests/qttest/tst_cabletarget.cpp @@ -43,6 +43,10 @@ The graphic draws them in a small box under the cable, the bundle staying together (RealTerminal::cableTarget()). + Also here: the number of a wire must stay in the room left between + its mark and the terminal -- it shrinks, and what does not fit is + clipped, so it never runs into the drawing of the terminal. + fixtures/every_feature.qet has the strip X1 (elements 891b70f2 and 4861e268) and the contact fc9cc920 wired to 891b70f2 by the conductor 8bd16d7a; the test gives the contact the Installation, @@ -159,6 +163,7 @@ private slots: void ownStripIsNoTarget(); void spareHasNoTarget(); void paintsWithTargetBox(); + void wireLabelStaysOutOfTheTerminal(); }; void tst_cabletarget::init() @@ -298,6 +303,74 @@ void tst_cabletarget::paintsWithTargetBox() QVERIFY(with_box != without_box); } +/** + The number of a wire is written next to its mark, in the room left + between the mark and the terminal: it shrinks to fit there, and what + still does not fit is clipped away, so a long number never runs into + the drawing of the terminal. The two pictures -- one with a number + long enough to reach into the terminal, one without any -- must be + the same above the bottom of the terminal, and differ below it (the + number is drawn somewhere). +*/ +void tst_cabletarget::wireLabelStaysOutOfTheTerminal() +{ + QVERIFY(wireCableToTheContact()); + + auto pattern_ = QSharedPointer{new TerminalStripLayoutPattern}; + const auto strips_ = m_project->terminalStrip(); + QVERIFY(!strips_.isEmpty()); + TerminalStripDrawer::TerminalStripDrawer drawer{ + QSharedPointer{ + new TerminalStripDrawer::TrueTerminalStrip{strips_.first()}}, + pattern_}; + + const QRectF bounds{drawer.boundingRect()}; + QVERIFY(!bounds.isEmpty()); + + const auto render = [&drawer, &bounds]() { + QImage image{bounds.size().toSize() + QSize{4, 4}, + QImage::Format_ARGB32_Premultiplied}; + image.fill(Qt::transparent); + QPainter painter{&image}; + painter.translate(-bounds.topLeft() + QPointF{2, 2}); + drawer.paint(&painter); + return image; + }; + + //A number much longer than the room left over the mark + Element *terminal_ = element( + QStringLiteral("{891b70f2-2822-41c3-9f94-28efb448b5c4}")); + QVERIFY(terminal_); + ElementData terminal_data_{terminal_->elementData()}; + terminal_data_.m_informations.addValue( + RealTerminal::cableWireInfoKey(), + QStringLiteral("gnge-gnge-gnge-gnge-gnge")); + terminal_->setElementData(terminal_data_); + const QImage with_label{render()}; + + //The same strip, the wire carries no number at all + terminal_data_.m_informations.addValue(RealTerminal::cableWireInfoKey(), + QString()); + terminal_->setElementData(terminal_data_); + const QImage without_label{render()}; + + //The number is drawn: the two pictures differ + QVERIFY(with_label != without_label); + + //The terminals of this strip all stand on the last level of the + //pattern, so their bottom is the same rectangle + const qreal terminal_bottom{pattern_->m_terminal_rect.at(3).bottom()}; + const auto rows_to_check{qMin(qRound(terminal_bottom - bounds.topLeft().y() + 2), + with_label.height())}; + for (auto y = 0 ; y < rows_to_check ; ++y) + { + for (auto x = 0 ; x < with_label.width() ; ++x) + { + QCOMPARE(with_label.pixel(x, y), without_label.pixel(x, y)); + } + } +} + int main(int argc, char **argv) { QStandardPaths::setTestModeEnabled(true);