Draw the cables in the realistic style too

The strip seen from above drew no cable at all: it had no zone for one
and no code to draw it, so a strip drawn realistically told nothing
about where its cables go while the same strip drawn schematically did.

The drawing itself was already shared between nothing -- it lived in
one style only, so it is now Helpers::drawCables() with its cells, and
both styles hand it the terminals they show. The realistic style
collects one wire exit per level spread over the width of the terminal
body, all of them leaving the strip at its bottom edge, and reserves
the zone under the strip for them as soon as one terminal carries a
cable, exactly like the schematic style does.

tst_cabletarget checks the realistic style paints under the body of
the strip when a terminal carries a cable, and drops that zone when it
does not.
This commit is contained in:
Kellermorph
2026-10-20 09:01:08 +02:00
parent 79ab711d93
commit 6e83012109
4 changed files with 166 additions and 16 deletions
@@ -522,6 +522,26 @@ struct BridgePoint
qreal width{0};
};
//True when at least one terminal of the strip carries a cable : the strip
//then needs the zone drawn under it to let the cables out, like the
//schematic style does.
bool haveCable(const AbstractTerminalStripInterface *strip)
{
if (!strip) {
return false;
}
for (const auto &physical_t : strip->physicalTerminal())
{
for (const auto &real_t : physical_t->realTerminals())
{
if (real_t && !real_t->cable().isEmpty()) {
return true;
}
}
}
return false;
}
} //End anonymous namespace
QRectF boundingRect(const AbstractTerminalStripInterface *strip,
@@ -535,7 +555,20 @@ QRectF boundingRect(const AbstractTerminalStripInterface *strip,
}
}
const qreal s_{pattern.m_realistic_px_per_mm};
return QRectF{0, 0, width_mm_ * s_, pattern.m_realistic_length_mm * s_};
const qreal length_{pattern.m_realistic_length_mm * s_};
//The cables are drawn under the strip, in the zone the schematic
//style reserves for them too
qreal extra_bottom_{0};
if (pattern.m_cable_wire_length > 0 && haveCable(strip))
{
//4 is the diameter of the circle at the end of the wires
extra_bottom_ = pattern.m_cable_wire_length
+ std::max<qreal>(0, pattern.m_cable_length)
+ std::max<qreal>(0, pattern.m_cable_end_length)
+ 4;
}
return QRectF{0, 0, width_mm_ * s_, length_ + extra_bottom_};
}
void paint(QPainter *painter,
@@ -595,6 +628,7 @@ void paint(QPainter *painter,
}
QHash<QUuid, QVector<BridgePoint>> bridges_;
QVector<Helpers::CableCell> cable_cells_;
for (const auto &g_ : geometry(&strip))
{
@@ -603,6 +637,24 @@ void paint(QPainter *painter,
const auto first_{g_.reals.first()};
const int levels_{static_cast<int>(g_.reals.size())};
//Cables (hoses) of this terminal : one wire exit by level, spread over
//the width of the body, all of them leaving the strip at its bottom edge
for (int k = 0 ; k < levels_ ; ++k)
{
const auto &real_t{g_.reals.at(k)};
if (!real_t || real_t->cable().isEmpty()) {
continue;
}
Helpers::CableCell cell_;
cell_.x = x_ + w_ * (k + 0.5) / levels_;
cell_.bottom = length_;
cell_.cable = real_t->cable();
cell_.wire = real_t->cableWire();
cell_.shield = real_t->isShield();
cell_.terminal = real_t;
cable_cells_.append(cell_);
}
//A terminal chosen in the catalog is drawn with its own clamp, so that a strip
//mixing screw and spring terminals is drawn as it is. The spring-cage clamps
//(opened with a screwdriver) are drawn like the push-in ones.
@@ -793,6 +845,18 @@ void paint(QPainter *painter,
draw_end_stop();
//The cables under the strip : the wires of a cable join it, and the
//cable ends together in the box naming where it goes -- drawn exactly
//like the schematic style draws them, so both styles tell the same thing
if (!cable_cells_.isEmpty())
{
painter->save();
painter->setFont(pattern.font());
painter->setPen(QPen(Qt::black, 0.5));
Helpers::drawCables(painter, cable_cells_, pattern);
painter->restore();
}
painter->restore();
}
@@ -29,6 +29,10 @@
namespace TerminalStripDrawer {
//The cells of a cable drawing live with the helpers, so both drawing
//styles build the same thing and pass it to Helpers::drawCables()
using Helpers::CableCell;
/**
* @brief TerminalStripDrawer::TerminalStripDrawer
* @param strip
@@ -259,20 +263,6 @@ void drawConnections(QPainter *painter, const QRectF &terminal_rect, qreal lengt
}
}
/**
* @brief The CableCell struct
* What is needed to draw the cable under a terminal.
*/
struct CableCell
{
qreal x{0}; ///< x of the middle of the terminal, in the strip coordinates
qreal bottom{0}; ///< y of the bottom of the terminal
QString cable; ///< name of the cable (hose)
QString wire; ///< color / number of the wire
bool shield{false}; ///< true if the terminal is the shield of the cable
QSharedPointer<AbstractRealTerminalInterface> terminal; ///< to ask where the cable goes
};
/**
* @brief drawCables
* Draw the cables under the terminals. Consecutive terminals who have the same cable name
@@ -941,6 +931,11 @@ void Helpers::drawTypeSymbol(QPainter *painter, const QRectF &box,
::TerminalStripDrawer::drawTypeSymbol(painter, box, type, led);
}
void Helpers::drawCables(QPainter *painter, const QVector<CableCell> &cells,
const TerminalStripLayoutPattern &pattern) {
::TerminalStripDrawer::drawCables(painter, cells, pattern);
}
/**
* @brief TerminalStripDrawer::paint
* @param painter
@@ -1368,7 +1363,7 @@ void TerminalStripDrawer::paint(QPainter *painter)
painter->setPen(cable_pen);
painter->setFont(m_pattern->font());
painter->setBrush(Qt::NoBrush);
drawCables(painter, cable_cells, *m_pattern);
Helpers::drawCables(painter, cable_cells, *m_pattern);
painter->restore();
}
}
@@ -42,6 +42,22 @@ namespace TerminalStripDrawer
//Symbol of the type of the terminal (fuse, diode, led...) scaled to fit in box
void drawTypeSymbol(QPainter *painter, const QRectF &box,
ElementData::TerminalType type, bool led);
//What is needed to draw the cable under a terminal
struct CableCell
{
qreal x{0}; ///< x of the middle of the terminal, in the strip coordinates
qreal bottom{0}; ///< y of the bottom of the terminal
QString cable; ///< name of the cable (hose)
QString wire; ///< color / number of the wire
bool shield{false}; ///< true if the terminal is the shield of the cable
QSharedPointer<AbstractRealTerminalInterface> terminal; ///< to ask where the cable goes
};
//Draw the cables under the terminals, whichever style draws them :
//consecutive terminals with the same cable share one cable, which ends
//together in a short stub and a box naming where it goes (see drawCables()
//in terminalstripdrawer.cpp for the whole drawing)
void drawCables(QPainter *painter, const QVector<CableCell> &cells,
const TerminalStripLayoutPattern &pattern);
}
}
+75
View File
@@ -17,6 +17,7 @@
*/
#include "qetapptest.h"
#include "TerminalStrip/GraphicsItem/realisticterminalstripdrawer.h"
#include "TerminalStrip/GraphicsItem/trueterminalstrip.h"
#include "TerminalStrip/physicalterminal.h"
#include "TerminalStrip/realterminal.h"
@@ -51,6 +52,10 @@
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.
Both drawing styles are covered: the schematic one and the
realistic one (the strip seen from above), which paint the same
cable through Helpers::drawCables().
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,
@@ -169,6 +174,7 @@ private slots:
void paintsWithTargetBox();
void wireLabelStaysOutOfTheTerminal();
void targetBoxKeepsTheDrawingFont();
void realisticStyleDrawsTheCable();
};
void tst_cabletarget::init()
@@ -445,6 +451,75 @@ void tst_cabletarget::targetBoxKeepsTheDrawingFont()
QVERIFY(lowest + 2 >= row);
}
/**
The realistic style draws the cable too. The strip seen from above
reserves the zone under it when one of its terminals carries a
cable, and the wires, the cable and the box naming where it goes
are painted in it -- exactly what the schematic style draws, since
both styles now share the same Helpers::drawCables().
*/
void tst_cabletarget::realisticStyleDrawsTheCable()
{
QVERIFY(wireCableToTheContact());
const auto strips_ = m_project->terminalStrip();
QVERIFY(!strips_.isEmpty());
const auto strip_ = QSharedPointer<TerminalStripDrawer::TrueTerminalStrip>{
new TerminalStripDrawer::TrueTerminalStrip{strips_.first()}};
TerminalStripLayoutPattern pattern_;
const auto bounds_of = [&strip_, &pattern_]() {
return TerminalStripDrawer::Realistic::boundingRect(strip_.data(),
pattern_);
};
const auto render = [&strip_, &pattern_](const QRectF &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});
TerminalStripDrawer::Realistic::paint(
&painter, *strip_, pattern_,
TerminalStripLayoutPattern::DrawStyle::RealisticPushIn);
return image;
};
const QRectF with_bounds{bounds_of()};
const QImage with_cable{render(with_bounds)};
//The body of the strip ends there : everything painted under it
//belongs to the cable
const qreal body_bottom{
pattern_.m_realistic_length_mm * pattern_.m_realistic_px_per_mm};
QVERIFY(with_bounds.height() > body_bottom);
int painted_{0};
for (auto y = qRound(body_bottom) + 4 ; y + 4 < with_cable.height() ; ++y)
{
for (auto x = 0 ; x + 4 < with_cable.width() ; ++x)
{
if (with_cable.pixel(x, y) != qRgba(0, 0, 0, 0)) {
++painted_;
}
}
}
//The wires and the cable are drawn in that zone
QVERIFY(painted_ > 0);
//The same strip, its terminal carries no cable name any more
Element *terminal_ = element(
QStringLiteral("{891b70f2-2822-41c3-9f94-28efb448b5c4}"));
QVERIFY(terminal_);
ElementData terminal_data_{terminal_->elementData()};
terminal_data_.m_informations.addValue(RealTerminal::cableInfoKey(),
QString());
terminal_->setElementData(terminal_data_);
//No cable to let out : the strip does not reserve the zone
const QRectF without_bounds{bounds_of()};
QVERIFY(without_bounds.height() < with_bounds.height());
}
int main(int argc, char **argv)
{
QStandardPaths::setTestModeEnabled(true);