Keep the texts of turned symbols horizontal, per project (#1335)

A project can now keep the texts drawn in its symbols, and the names of
their terminals, horizontal when a symbol is turned: Project properties >
General, "Garder horizontaux les textes des symboles pivotés". The box of
each text turns with the symbol; the text does not, and reads as it does
in the symbol itself.

It is a project setting, saved as <symbol_texts upright="true"/> and
only when on. A new project starts with it on; a project saved without
it (every existing one) reads with it off, so it looks and saves exactly
as before, and looks the same on every computer. The MCP server's new
projects start with it on too.

It builds on the mirror of #1354, which already redraws the texts of a
mirrored symbol readable: what the symbol does to its texts is now its
mirrors and, with the setting on, its turn (Element::symbolTextsTransform()).
ElementPictureFactory caches one drawing per such transform, terminal
names undo it the same way, and the DXF export places the texts alike.

The fields of a symbol (label, comment...) already keep their angle with
"Garder la rotation visuelle" and are left as they are.

Known limit: two texts stacked in a symbol end up side by side when it is
turned, and can overlap when kept horizontal; the setting can be turned
off for such a project.

Test: tst_uprightsymboltexts turns the symbols of a folio and checks the
angle of each motor's "M" in the DXF, with the setting off and on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-07 12:43:04 +13:00
parent a3b1468b0f
commit 592cbdbf0b
14 changed files with 428 additions and 93 deletions
+5 -1
View File
@@ -3567,7 +3567,11 @@ def tool_project_new(binary: str, output: str, title: str = "Untitled",
out.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory(prefix="qet-mcp-new-") as tmp:
skeleton = Path(tmp) / "skeleton.qet"
skeleton.write_text('<project version="0.100.0" title=%s>\n</project>\n'
# <symbol_texts>: a project made in QElectroTech starts with the texts
# of its turned symbols kept horizontal; one read from a file without
# it does not, so say it here as QElectroTech would have
skeleton.write_text('<project version="0.100.0" title=%s>\n'
' <symbol_texts upright="true"/>\n</project>\n'
% quoteattr(title), encoding="utf-8")
result = _run_qet(binary, [str(skeleton)], timeout=timeout,
elements_dir=elements_dir, script="\n".join(script), tail=200_000)
+7
View File
@@ -4299,6 +4299,13 @@ class Integration(unittest.TestCase):
self.assertEqual(r["project"]["title"], 'A "b" & <c>')
self.assertEqual([f["title"] for f in r["project"]["folios"]], ["Power", "Control"])
def test_new_project_keeps_symbol_texts_horizontal(self):
"""Like a project made in QElectroTech, and kept by its save."""
r = m.tool_project_new(BINARY, self.sb.p("u.qet"), title="U", folios=1)
self.assertTrue(r["ok"])
root = ET.parse(r["output"]).getroot()
self.assertEqual(root.find("symbol_texts").get("upright"), "true")
def test_new_project_with_zero_folios(self):
r = m.tool_project_new(BINARY, self.sb.p("z.qet"), title="Z", folios=0)
self.assertTrue(r["ok"])