Merge pull request #1287 from ispyisail/fix/xref-bottom-stack

Fix cross-references printing over each other at the folio bottom (#1178)
This commit is contained in:
ispyisail
2026-10-04 10:55:24 +13:00
committed by GitHub
2 changed files with 66 additions and 5 deletions
+65 -5
View File
@@ -117,6 +117,7 @@ void CrossRefItem::setUpConnection()
set=true;
else if(m_properties.snapTo() == XRefProperties::Bottom && !m_text && !m_group) //Snap to bottom of element and parent is the element itself
{
m_update_connection << connect(m_element, &Element::xChanged, this, &CrossRefItem::autoPos);
m_update_connection << connect(m_element, &Element::yChanged, this, &CrossRefItem::autoPos);
m_update_connection << connect(m_element, &Element::rotationChanged, this, &CrossRefItem::autoPos);
set=true;
@@ -329,15 +330,74 @@ void CrossRefItem::autoPos()
//We calculate the position according to the snapTo of the xrefproperties
if (m_properties.snapTo() == XRefProperties::Bottom)
QGIUtility::centerToBottomDiagram(this,
m_element,
m_properties.offset() <= 40
? 5
: m_properties.offset());
stackAtBottom();
else
QGIUtility::centerToParentBottom(this);
}
/**
@brief CrossRefItem::stackAtBottom
Places every cross reference of this folio that snaps to the bottom.
Each one is centred under its element at the bottom of the folio, and
when two would overlap, the one of the higher element goes above the
other: several coils in one column get their crosses stacked in the
same order as the coils, instead of all on the same spot.
*/
void CrossRefItem::stackAtBottom()
{
Diagram *diagram = m_element->diagram();
if (!diagram) return;
QList<CrossRefItem *> xrefs;
for (QGraphicsItem *item : diagram->items()) {
if (item->type() != CrossRefItem::Type) continue;
auto xref = static_cast<CrossRefItem *>(item);
if (xref->m_properties.snapTo() == XRefProperties::Bottom
&& !xref->m_text && !xref->m_group
&& xref->m_element->elementData().m_master_type != ElementData::PLC)
xrefs << xref;
}
if (!xrefs.contains(this)) xrefs << this;
// The lowest element first, so it keeps the bottom of the folio.
// Position, then uuid, so the order is the same on every load.
std::sort(xrefs.begin(), xrefs.end(),
[](const CrossRefItem *a, const CrossRefItem *b) {
const QPointF pa = a->m_element->sceneBoundingRect().center();
const QPointF pb = b->m_element->sceneBoundingRect().center();
if (pa.y() != pb.y()) return pa.y() > pb.y();
if (pa.x() != pb.x()) return pa.x() < pb.x();
return a->m_element->uuid() < b->m_element->uuid();
});
const qreal gap = 5;
QList<QRectF> placed;
for (CrossRefItem *xref : std::as_const(xrefs)) {
const qreal offset = xref->m_properties.offset();
QGIUtility::centerToBottomDiagram(xref, xref->m_element,
offset <= 40 ? 5 : offset);
if (xref->boundingRect().isEmpty()) continue;
// Move up past every cross already placed that it would overlap.
QRectF rect = xref->sceneBoundingRect();
const qreal bottom = rect.bottom();
for (bool moved = true; moved; ) {
moved = false;
for (const QRectF &other : std::as_const(placed))
if (rect.left() < other.right() && other.left() < rect.right()
&& rect.top() < other.bottom() + gap
&& other.top() - gap < rect.bottom()) {
rect.moveBottom(other.top() - gap);
moved = true;
}
}
if (rect.bottom() != bottom)
xref->setPos(xref->parentItem()->mapFromScene(
xref->scenePos() + QPointF(0, rect.bottom() - bottom)));
placed << rect;
}
}
/**
@brief CrossRefItem::sceneEvent
@param event
+1
View File
@@ -58,6 +58,7 @@ class CrossRefItem : public QGraphicsObject
private:
void init();
void setUpConnection();
void stackAtBottom();
public:
enum { Type = UserType + 1009 };