Merge master: add cli_export, pdf_links; EDZ: 10-slot grid, group headers, ToS notice

- Resolve cmake/qet_compilation_vars.cmake conflict: keep both upstream's
  cli_export.cpp/h and pdf_links.cpp/h and the EDZ source additions.

- 10-position grid alignment: pin_y values are multiples of 10 so terminals
  snap cleanly to QET's default grid.  group_gap raised to 10 (one full slot).

- Named connector groups get a header label (group name) placed in the gap
  above the first pin, so the electrician sees block names (XDI, XPOW, …)
  without reading individual terminal designations.

- Device-tag dynamic_text now uses 9pt LABEL_FONT and y = min_y - 9 so it
  clears the element body and is legible at normal zoom.

- Add EPLAN Data Portal Terms of Use disclaimer to sources/import/edz/README.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Shane Ringrose
2026-06-21 21:00:49 +12:00
70 changed files with 6651 additions and 4941 deletions
+25 -4
View File
@@ -34,6 +34,8 @@ const QString FONT =
QStringLiteral("Liberation Sans,5,-1,5,50,0,0,0,0,0,Regular");
const QString TITLE_FONT =
QStringLiteral("Liberation Sans,5,-1,5,75,0,0,0,0,0,Bold");
const QString LABEL_FONT =
QStringLiteral("Liberation Sans,9,-1,5,50,0,0,0,0,0,Regular");
QString uuidStr()
{
@@ -71,19 +73,25 @@ QDomDocument EdzElementBuilder::build(const EdzPart &part)
}
const int n = pins.size();
const int pitch = 10;
const int group_gap = 5; // extra px inserted between designation groups
const int group_gap = 10; // one full slot between named connector groups
// Pins arrive sorted by functional group then by designation within each
// group (see EdzPart::parse). A group break occurs when the
// functiondefinition block changes; fall back to designation comparison for
// parts that carry no functiondefinition information.
// No gap is inserted for power/busbar pins that carry no group label —
// they flow consecutively so a 3-phase AC source stays connected.
auto groupKey = [](const EdzPin &p) {
return p.group.isEmpty() ? p.designation : p.group;
};
QVector<bool> is_group_break(n, false);
for (int i = 1; i < n; ++i)
is_group_break[i] = (groupKey(pins.at(i)) != groupKey(pins.at(i - 1)));
is_group_break[i] = (groupKey(pins.at(i)) != groupKey(pins.at(i - 1)))
&& (!pins.at(i).group.isEmpty());
// Place every terminal on a multiple-of-10 y coordinate so they align
// cleanly with QET's default grid. The gap slot is also 10 px, giving
// one empty grid row between connector groups.
QVector<int> pin_y(n);
int cur_y = 0;
for (int i = 0; i < n; ++i) {
@@ -218,10 +226,23 @@ QDomDocument EdzElementBuilder::build(const EdzPart &part)
desc.appendChild(makeText(doc, 6, pin_y[i] + 2, label, FONT));
}
// Connector group header labels — one per named group, in the gap above
// the group's first pin so the electrician can see the terminal block name
// (e.g. "XDI", "XPOW") without having to read individual terminal names.
for (int i = 0; i < n; ++i) {
if (pins.at(i).group.isEmpty()) continue;
if (i > 0 && groupKey(pins.at(i)) == groupKey(pins.at(i - 1))) continue;
// Place the label centred in the gap slot above the group's first pin.
const int label_y = (i == 0) ? (pin_y[0] - group_gap / 2)
: (pin_y[i] - group_gap / 2);
desc.appendChild(makeText(doc, body_left + 2, label_y,
pins.at(i).group, FONT));
}
// Device-tag label (per-instance, above the body).
QDomElement dyn = doc.createElement(QStringLiteral("dynamic_text"));
dyn.setAttribute(QStringLiteral("x"), min_x + pad);
dyn.setAttribute(QStringLiteral("y"), min_y - 2);
dyn.setAttribute(QStringLiteral("y"), min_y - 9);
dyn.setAttribute(QStringLiteral("z"), QStringLiteral("5"));
dyn.setAttribute(QStringLiteral("text_width"), QStringLiteral("-1"));
dyn.setAttribute(QStringLiteral("Halignment"), QStringLiteral("AlignLeft"));
@@ -231,7 +252,7 @@ QDomDocument EdzElementBuilder::build(const EdzPart &part)
dyn.setAttribute(QStringLiteral("keep_visual_rotation"), QStringLiteral("false"));
dyn.setAttribute(QStringLiteral("text_from"), QStringLiteral("ElementInfo"));
dyn.setAttribute(QStringLiteral("uuid"), uuidStr());
dyn.setAttribute(QStringLiteral("font"), FONT);
dyn.setAttribute(QStringLiteral("font"), LABEL_FONT);
dyn.appendChild(doc.createElement(QStringLiteral("text")));
QDomElement info_name = doc.createElement(QStringLiteral("info_name"));
info_name.appendChild(doc.createTextNode(QStringLiteral("label")));