From 799ff5573fa5f74037c6d869eec9718cb120a1fa Mon Sep 17 00:00:00 2001 From: ispyisail Date: Wed, 9 Sep 2026 11:45:36 +1200 Subject: [PATCH 1/2] Revert the isFull() change: max_slaves counts slots, not contacts The earlier commit changed MasterElement::isFull() to compare the contacts in use against max_slaves. That was wrong, and this restores the original comparison against the number of linked elements. max_slaves is a number of slots, not of contacts: - it sizes the contact group table in the element editor, one row per slot (ElementPropertiesEditorWidget::populateSlaveGroupsTable) - a group must match the slave's own contact count before it can be chosen, so a 4 pole slave needs a group declaring 4 and occupies that single group (ContactGroupSelectionDialog) - each slave stores exactly one group index (Element::setGroupIndexForElement) So a coil declaring 4 slots accepts 4 slaves, whatever their pole count. Counting contacts made one 4 pole slave fill a 4 slot coil on its own and refuse three further links that should have been allowed. ContactUsage stays, and its per-type tally is still what the General tab needs: how many contacts an auxiliary block must provide is a different question from how many slots are occupied, and only the former wants the pole multiplier. The header now says so. Co-Authored-By: Claude Opus 5 --- sources/contactusage.h | 6 ++++++ sources/qetgraphicsitem/masterelement.cpp | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/sources/contactusage.h b/sources/contactusage.h index 5b29176ca..406a6223a 100644 --- a/sources/contactusage.h +++ b/sources/contactusage.h @@ -29,6 +29,12 @@ rules can be unit tested on their own. MasterElement::contactUsage() is the thin wrapper that feeds it the linked elements. + This counts contacts, which is what tells you how many contacts an + auxiliary block must provide. It is deliberately not the count that + MasterElement::isFull() uses: a master's max_slaves is a number of + slots, and a slave fills exactly one slot however many contacts it + carries. + Two rules are easy to get wrong, and both live here so that every caller gets them right: - a slave stands for as many contacts as its "number" kind diff --git a/sources/qetgraphicsitem/masterelement.cpp b/sources/qetgraphicsitem/masterelement.cpp index 1ccebfd3a..599b8c90d 100644 --- a/sources/qetgraphicsitem/masterelement.cpp +++ b/sources/qetgraphicsitem/masterelement.cpp @@ -282,8 +282,11 @@ bool MasterElement::isFull() const return false; } - // Return true if the contacts already used reached or exceeded the limit - return contactUsage().total() >= max_slaves; + // max_slaves is a number of slots, not of contacts: it sizes the + // element's contact group table, and a slave occupies exactly one + // group however many contacts that group stands for. So the slots + // in use are the linked elements, not the contacts they carry. + return connected_elements.size() >= max_slaves; } /** From 73e9473db4a405596c42d3c2b58fdfcf36e90375 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Wed, 9 Sep 2026 11:46:34 +1200 Subject: [PATCH 2/2] Keep the slave total in slots, and label the breakdown as contacts Two units were being stacked in the same block. The line above reports max_slaves, which is a number of slots, so reporting the line below in contacts made a coil with one 4 pole slave read "maximum 4 / used 4" while three slots were still free. The total goes back to counting linked elements, matching the unit of the line above it and restoring the original behaviour of that line. The per-type breakdown keeps the pole multiplier, because that is the question it answers -- how many contacts an auxiliary block must provide -- and is now prefixed "Contacts :" so the two units are not mistaken for each other. Co-Authored-By: Claude Opus 5 --- sources/ui/elementpropertieswidget.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sources/ui/elementpropertieswidget.cpp b/sources/ui/elementpropertieswidget.cpp index 2dc75cd51..9091dadbb 100644 --- a/sources/ui/elementpropertieswidget.cpp +++ b/sources/ui/elementpropertieswidget.cpp @@ -390,20 +390,20 @@ QWidget *ElementPropertiesWidget::generalWidget() ? QString(tr("Nombre maximum de contacts esclaves définis : non défini\n")) : QString(tr("Nombre maximum de contacts esclaves définis : %1\n")).arg(max_slaves); - //Counted in contacts rather than in linked elements, so that a - //slave standing for several contacts is reported as the number - //of contacts it actually uses. + //Left as a count of linked elements: the line above is a number + //of slots, and a slave fills one slot however many contacts it + //carries, so the two stay in the same unit. + description_string += QString(tr("Nombre de contacts esclaves utilisés : %1\n")).arg(m_element->linkedElements().count()); + const ContactUsage usage = static_cast(m_element.data())->contactUsage(); - description_string += QString(tr("Nombre de contacts esclaves utilisés : %1\n")).arg(usage.total()); - //The breakdown is what tells you which auxiliary block would //satisfy this coil, so it is only worth printing once there is //something to break down. if (usage.total() > 0) { - description_string += QString(tr(" NO : %1, NC : %2, inverseurs : %3, autres : %4\n")) + description_string += QString(tr(" Contacts : NO : %1, NC : %2, inverseurs : %3, autres : %4\n")) .arg(usage.no) .arg(usage.nc) .arg(usage.sw)