diff --git a/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.h b/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.h index 4dc941601..9a17f1df3 100644 --- a/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.h +++ b/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.h @@ -127,8 +127,11 @@ class TerminalStripLayoutPattern qreal m_cable_wire_length{40}; //Length of the cable qreal m_cable_length{60}; - //Length of the wires after the cable - qreal m_cable_end_length{40}; + //Length of the wires after the cable. It leaves the room the box + //naming where the cable goes needs: three lines (Installation, + //Location, Label) at the default font of 15 px, so the box does + //not have to shrink its text down. + qreal m_cable_end_length{80}; qreal m_bridge_point_d{5}; QVector m_bridge_point_y_offset{50,70,90,110}; diff --git a/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp b/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp index fc343ac7c..70c5fe7da 100644 --- a/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp +++ b/sources/TerminalStrip/GraphicsItem/terminalstripdrawer.cpp @@ -395,8 +395,9 @@ void drawCables(QPainter *painter, const QVector &cells, const Termin //The bundle stays together at the end: the cross bar, a short //stub, and a box naming where the cable goes -- the Installation, //Location and Label (BMK) of the piece it lands on, the same - //three fields the cable list shows. The lines shrink to the end - //zone the settings leave, so the box never grows past the strip. + //three fields the cable list shows. The box spans the cross bar + //and never shrinks its text down to fit: when its lines are + //longer than the cross bar, the box is the one which grows. painter->drawLine(QPointF{min_x, bar_2_y}, QPointF{max_x, bar_2_y}); const qreal stub{qMin(6, end_length)}; painter->drawLine(QPointF{cable_x, bar_2_y}, QPointF{cable_x, bar_2_y + stub}); @@ -405,23 +406,30 @@ void drawCables(QPainter *painter, const QVector &cells, const Termin : QVector()}; if (!target_lines.isEmpty() && end_length - stub > 4) { + //The font of the drawing, shrunk only while the lines do not + //fit the height the settings leave for the box + const qreal room{end_length - stub}; QFont box_font{painter->font()}; if (box_font.pixelSize() <= 0 && box_font.pointSizeF() > 0) { box_font.setPixelSize(qMax(4, qRound(box_font.pointSizeF() * 96.0 / 72.0))); } - const qreal room{end_length - stub}; - const auto fits_the_end_zone = [&target_lines, room](const QFont &font_) { + const auto fits_the_height = [&target_lines, room](const QFont &font_) { return QFontMetricsF{font_}.height() * target_lines.size() + 4 <= room; }; - while (!fits_the_end_zone(box_font) && box_font.pixelSize() > 4) { + while (!fits_the_height(box_font) && box_font.pixelSize() > 4) { box_font.setPixelSize(box_font.pixelSize() - 1); } + //As wide as the cross bar the cable ends on -- the strip of + //one single terminal has no width to take, so a small floor + //keeps the box drawn at all -- and wider still when the lines + //of the target are longer than that const QFontMetricsF box_metrics{box_font}; - qreal box_width{6}; + qreal box_width{qMax(max_x - min_x, 16)}; for (const QString &line_ : target_lines) { box_width = qMax(box_width, box_metrics.horizontalAdvance(line_) + 6); } + const qreal box_height{box_metrics.height() * target_lines.size() + 4}; const QRectF box{cable_x - box_width / 2, bar_2_y + stub, box_width, box_height}; @@ -430,9 +438,9 @@ void drawCables(QPainter *painter, const QVector &cells, const Termin painter->drawRect(box); for (auto i = 0 ; i < target_lines.size() ; ++i) { - painter->drawText(QRectF{box.left() + 1, + painter->drawText(QRectF{box.left() + 3, box.top() + 2 + i * box_metrics.height(), - box.width() - 2, box_metrics.height()}, + box.width() - 6, box_metrics.height()}, Qt::AlignCenter, target_lines.at(i)); } diff --git a/tests/qttest/tst_cabletarget.cpp b/tests/qttest/tst_cabletarget.cpp index 1ca83a347..ee1ef2dbf 100644 --- a/tests/qttest/tst_cabletarget.cpp +++ b/tests/qttest/tst_cabletarget.cpp @@ -47,6 +47,10 @@ its mark and the terminal -- it shrinks, and what does not fit is clipped, so it never runs into the drawing of the terminal. + Also here: the box at the end of a cable is written at the font of + the drawing -- the end zone the settings leave is what gives it the + room, so three lines never end up squeezed into a tiny text. + 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, @@ -164,6 +168,7 @@ private slots: void spareHasNoTarget(); void paintsWithTargetBox(); void wireLabelStaysOutOfTheTerminal(); + void targetBoxKeepsTheDrawingFont(); }; void tst_cabletarget::init() @@ -371,6 +376,75 @@ void tst_cabletarget::wireLabelStaysOutOfTheTerminal() } } +/** + The box at the end of a cable keeps the font of the drawing: with + its three lines (Installation, Location and Label) and the end zone + the settings leave, the text is still written at the font of the + strip instead of being squeezed into a tiny one. The box is the + lowest thing the strip draws, so its bottom line is the lowest + painted row, and it must land where three lines of that font need + it to. +*/ +void tst_cabletarget::targetBoxKeepsTheDrawingFont() +{ + 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()); + 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); + painter.end(); + + qreal lowest{-1}; + for (auto y = 0 ; y < image.height() ; ++y) + { + for (auto x = 0 ; x < image.width() ; ++x) + { + if (image.pixel(x, y) != qRgba(0, 0, 0, 0)) { + lowest = y; + break; + } + } + } + QVERIFY(lowest >= 0); + + //The end zone the default layout leaves is what gives the box its + //room: three lines of the default font must fit in it, or the text + //of a target is squeezed down again by the drawing itself + const QFontMetricsF metrics{pattern_->font()}; + const qreal room{pattern_->m_cable_end_length + - qMin(6, pattern_->m_cable_end_length)}; + QVERIFY2(metrics.height() * 3 + 4 <= room, + "the default end zone leaves no room for three lines of the " + "default font, a target would be squeezed again"); + + //Where the bottom line of the box lands when it holds the three + //lines of its text at the font of the drawing + const qreal terminals_bottom{pattern_->m_terminal_rect.at(3).bottom()}; + const qreal bar_2{terminals_bottom + pattern_->m_cable_wire_length + + pattern_->m_cable_length}; + const qreal box_bottom{bar_2 + qMin(6, pattern_->m_cable_end_length) + + metrics.height() * 3 + 4}; + + //The strip draws nothing under the box, so the lowest painted row + //is its bottom line -- within a pixel, the outline of a rectangle + //is painted on its edge + const qreal row{box_bottom - bounds.top() + 2}; + QVERIFY(lowest + 2 >= row); +} + int main(int argc, char **argv) { QStandardPaths::setTestModeEnabled(true);