Size the cable target box to the cross bar

The box hugged its own text, so it stayed small whatever room the end
zone gave, and its font shrank until the three lines squeezed into it.
It now spans the cross bar the cable bundle ends on -- the width the
strip already draws there -- and keeps the font of the drawing: when
its lines (Installation, Location and Label) are longer than that cross
bar, it is the box which grows, the text is never cut down to fit a box.
The end zone of the default layout leaves the room those three lines
need at that font, so a target is not squeezed by the drawing itself.
The setting still rules it: a smaller zone shrinks the text again.

tst_cabletarget checks the box is drawn three lines tall at the font
of the drawing, and that the default zone leaves that room.
This commit is contained in:
Kellermorph
2026-10-20 09:00:58 +02:00
parent 3de7f525cc
commit 79ab711d93
3 changed files with 95 additions and 10 deletions
@@ -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<qreal> m_bridge_point_y_offset{50,70,90,110};
@@ -395,8 +395,9 @@ void drawCables(QPainter *painter, const QVector<CableCell> &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<qreal>(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<CableCell> &cells, const Termin
: QVector<QString>()};
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<qreal>(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<CableCell> &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));
}
+74
View File
@@ -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<TerminalStripLayoutPattern>{new TerminalStripLayoutPattern};
const auto strips_ = m_project->terminalStrip();
QVERIFY(!strips_.isEmpty());
TerminalStripDrawer::TerminalStripDrawer drawer{
QSharedPointer<TerminalStripDrawer::TrueTerminalStrip>{
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<qreal>(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<qreal>(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);