crossrefitem: fix SIGSEGV when dropping power NC contact on diagram

Three bugs were causing a crash (SIGSEGV in QRegion::begin) when
a power NC slave element was placed on a folio, even before linking
it to a master element.

1. m_drawing (QPicture) was never reset between updateLabel() calls.
   QPicture accumulates paint commands — calling qp.begin() on an
   existing QPicture appends to it rather than replacing its content.
   After several updates (load, move, hover...) the picture became
   corrupted and crashed on play().
   Fix: reset m_drawing = QPicture() at the start of updateLabel().

2. m_drawed_contacts was only initialized to 0 in drawAsContacts(),
   but not in drawAsCross(). When drawing in Cross mode, fillCrossRef()
   called drawContact() with an uninitialized m_drawed_contacts value,
   producing a garbage offset. The NC contact symbol uses drawPolyline()
   with a sub-pixel Y coordinate (offset+2.5); with a random offset Qt
   generated an invalid QRegion and crashed.
   This explains why NC contacts crashed but NO contacts did not: the
   NO symbol only uses drawLine() which is more tolerant of bad coords.
   Fix: add m_drawed_contacts = 0 at the start of drawAsCross().

3. setUpCrossBoundingRect() used QRectF() (null rect) as the reference
   rect for painter.boundingRect(), which can return invalid dimensions.
   Additionally, height was accumulated incorrectly: united() + setHeight()
   doubled the height at each iteration, causing an exponentially growing
   bounding rect with multiple contacts.
   Fix: use QRectF(0, 0, 500, 20) as reference rect and accumulate
   height and width independently.
This commit is contained in:
Laurent Trinques
2026-05-23 15:32:28 +02:00
parent dbda958261
commit d949e6eb8c

View File

@@ -222,6 +222,9 @@ void CrossRefItem::updateLabel()
prepareGeometryChange(); prepareGeometryChange();
m_bounding_rect = QRectF(); m_bounding_rect = QRectF();
//Reset QPicture so it doesn't accumulate commands across updates
m_drawing = QPicture();
//init the painter //init the painter
QPainter qp; QPainter qp;
qp.begin(&m_drawing); qp.begin(&m_drawing);
@@ -585,9 +588,10 @@ void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
QRectF no_bounding; QRectF no_bounding;
for (auto str : no_str) for (auto str : no_str)
{ {
QRectF bounding = painter.boundingRect(QRectF (), Qt::AlignCenter, str); QRectF bounding = painter.boundingRect(QRectF(0, 0, 500, 20), Qt::AlignLeft, str);
no_bounding = no_bounding.united(bounding);
no_bounding.setHeight(no_bounding.height() + bounding.height()); no_bounding.setHeight(no_bounding.height() + bounding.height());
if (bounding.width() > no_bounding.width())
no_bounding.setWidth(bounding.width());
} }
//Adjust according to the NO //Adjust according to the NO
if (no_bounding.height() > default_bounding.height() - header) if (no_bounding.height() > default_bounding.height() - header)
@@ -599,9 +603,10 @@ void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
QRectF nc_bounding; QRectF nc_bounding;
for (auto str : nc_str) for (auto str : nc_str)
{ {
QRectF bounding = painter.boundingRect(QRectF (), Qt::AlignCenter, str); QRectF bounding = painter.boundingRect(QRectF(0, 0, 500, 20), Qt::AlignLeft, str);
nc_bounding = nc_bounding.united(bounding);
nc_bounding.setHeight(nc_bounding.height() + bounding.height()); nc_bounding.setHeight(nc_bounding.height() + bounding.height());
if (bounding.width() > nc_bounding.width())
nc_bounding.setWidth(bounding.width());
} }
//Adjust according to the NC //Adjust according to the NC
if (nc_bounding.height() > default_bounding.height() - header) if (nc_bounding.height() > default_bounding.height() - header)
@@ -625,6 +630,7 @@ void CrossRefItem::drawAsCross(QPainter &painter)
{ {
//calculate the size of the cross //calculate the size of the cross
setUpCrossBoundingRect(painter); setUpCrossBoundingRect(painter);
m_drawed_contacts = 0;
m_hovered_contacts_map.clear(); m_hovered_contacts_map.clear();
//Bounding rect is empty that mean there's no contact to draw //Bounding rect is empty that mean there's no contact to draw