174 lines
7.1 KiB
Python
174 lines
7.1 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
# -*- coding: utf-8 -*-
|
||
|
|
"""
|
||
|
|
patch_render_engine_c3b.py — Chantier C3b (centrage vertical)
|
||
|
|
=============================================================
|
||
|
|
Corrige deux défauts de centrage vertical révélés par les previews C2,
|
||
|
|
SANS toucher au helper _cy() (le centrage du contenu dans la zone est
|
||
|
|
un choix de design assumé — le contenu respire).
|
||
|
|
|
||
|
|
P1. big_stat : la hauteur de bloc était codée en dur (block = 8.13),
|
||
|
|
sous-estimée par rapport au placement réel (chiffre à y, desc à
|
||
|
|
y+5.33, source à y+7.37 ≈ 8.3+). Résultat : _cy() centrait un
|
||
|
|
bloc faussé, l'ensemble penchait vers le bas. Correctif : hauteur
|
||
|
|
réelle calculée (avec/sans source) → centrage exact. Les offsets
|
||
|
|
internes deviennent relatifs à cette hauteur.
|
||
|
|
|
||
|
|
P2. executive_summary : dans chaque carte (hauteur ch=3.68), le label
|
||
|
|
et le texte étaient posés à des offsets FIXES (y+0.56, y+1.57),
|
||
|
|
collés en haut, laissant du vide en bas de carte. Correctif : le
|
||
|
|
bloc label+texte est centré verticalement dans la carte (offsets
|
||
|
|
dérivés de ch), à côté du badge déjà centré.
|
||
|
|
|
||
|
|
Aucune dépendance nouvelle ; réutilise measure via estimate_text_height
|
||
|
|
déjà présent. Vérifie chaque ancre, écrit .bak-c3b, compile, idempotent.
|
||
|
|
|
||
|
|
Usage (dossier du pipeline, single-line) :
|
||
|
|
python3 patch_render_engine_c3b.py
|
||
|
|
"""
|
||
|
|
|
||
|
|
import py_compile
|
||
|
|
import shutil
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
TARGET = Path("render_engine_v2.py")
|
||
|
|
|
||
|
|
PATCHES = [
|
||
|
|
# P1 — big_stat : hauteur réelle
|
||
|
|
(
|
||
|
|
' def _render_big_stat(self, slide, d):\n'
|
||
|
|
' self._title(slide, pick(d, "titre", "title"))\n'
|
||
|
|
' val = pick(d, "valeur", "stat", "chiffre", "value")\n'
|
||
|
|
' desc = pick(d, "description", "texte", "label")\n'
|
||
|
|
' src = pick(d, "source", "reference")\n'
|
||
|
|
' block = 8.13\n'
|
||
|
|
' y = self._cy(block)\n'
|
||
|
|
' self._text(slide, 0, y, self.SLIDE_W, 5.1, val,\n'
|
||
|
|
' font=self.F_DISPLAY, size=self.T["stat_hero"], '
|
||
|
|
'bold=True,\n'
|
||
|
|
' color=self.C["coral"], align=PP_ALIGN.CENTER,\n'
|
||
|
|
' anchor=MSO_ANCHOR.MIDDLE)\n'
|
||
|
|
' self._text(slide, 6.86, y + 5.33, self.SLIDE_W - 13.72, '
|
||
|
|
'2.0, desc,\n'
|
||
|
|
' size=18, color=self.C["body"], '
|
||
|
|
'align=PP_ALIGN.CENTER)\n'
|
||
|
|
' if src:\n'
|
||
|
|
' self._text(slide, 6.86, y + 7.37, self.SLIDE_W - '
|
||
|
|
'13.72, 0.9, src,\n'
|
||
|
|
' size=11, italic=True, '
|
||
|
|
'color=self.C["muted"],\n'
|
||
|
|
' align=PP_ALIGN.CENTER)\n',
|
||
|
|
|
||
|
|
' def _render_big_stat(self, slide, d):\n'
|
||
|
|
' self._title(slide, pick(d, "titre", "title"))\n'
|
||
|
|
' val = pick(d, "valeur", "stat", "chiffre", "value")\n'
|
||
|
|
' desc = pick(d, "description", "texte", "label")\n'
|
||
|
|
' src = pick(d, "source", "reference")\n'
|
||
|
|
' # Hauteur réelle du bloc (C3b) : chiffre + desc '
|
||
|
|
'(+ source)\n'
|
||
|
|
' H_VAL, GAP_D, H_DESC, GAP_S, H_SRC = 5.1, 0.23, 2.0, '
|
||
|
|
'0.14, 0.9\n'
|
||
|
|
' block = H_VAL + GAP_D + H_DESC + (\n'
|
||
|
|
' GAP_S + H_SRC if src else 0.0)\n'
|
||
|
|
' y = self._cy(block)\n'
|
||
|
|
' self._text(slide, 0, y, self.SLIDE_W, H_VAL, val,\n'
|
||
|
|
' font=self.F_DISPLAY, size=self.T["stat_hero"], '
|
||
|
|
'bold=True,\n'
|
||
|
|
' color=self.C["coral"], align=PP_ALIGN.CENTER,\n'
|
||
|
|
' anchor=MSO_ANCHOR.MIDDLE)\n'
|
||
|
|
' y_desc = y + H_VAL + GAP_D\n'
|
||
|
|
' self._text(slide, 6.86, y_desc, self.SLIDE_W - 13.72, '
|
||
|
|
'H_DESC, desc,\n'
|
||
|
|
' size=18, color=self.C["body"], '
|
||
|
|
'align=PP_ALIGN.CENTER)\n'
|
||
|
|
' if src:\n'
|
||
|
|
' y_src = y_desc + H_DESC + GAP_S\n'
|
||
|
|
' self._text(slide, 6.86, y_src, self.SLIDE_W - 13.72, '
|
||
|
|
'H_SRC, src,\n'
|
||
|
|
' size=11, italic=True, '
|
||
|
|
'color=self.C["muted"],\n'
|
||
|
|
' align=PP_ALIGN.CENTER)\n',
|
||
|
|
),
|
||
|
|
# P2 — executive_summary : bloc label+texte centré dans la carte
|
||
|
|
(
|
||
|
|
' self._text(slide, self.MX + 3.81, y + 0.56, 8.1, 1.0, '
|
||
|
|
'label,\n'
|
||
|
|
' size=14, bold=True, color=col, '
|
||
|
|
'char_spacing=3)\n'
|
||
|
|
' self._text(slide, self.MX + 3.81, y + 1.57,\n'
|
||
|
|
' self.SLIDE_W - 2 * self.MX - 5.33, 1.8, '
|
||
|
|
'txt,\n'
|
||
|
|
' size=self.T["body"], '
|
||
|
|
'color=self.C["body"])\n',
|
||
|
|
|
||
|
|
' # Bloc label+texte centré verticalement dans la carte '
|
||
|
|
'(C3b)\n'
|
||
|
|
' H_LBL, GAP_LT, H_TXT = 0.85, 0.18, 1.8\n'
|
||
|
|
' blk = H_LBL + GAP_LT + H_TXT\n'
|
||
|
|
' y_lbl = y + max(0.0, (ch - blk) / 2)\n'
|
||
|
|
' self._text(slide, self.MX + 3.81, y_lbl, 8.1, H_LBL, '
|
||
|
|
'label,\n'
|
||
|
|
' size=14, bold=True, color=col, '
|
||
|
|
'char_spacing=3,\n'
|
||
|
|
' anchor=MSO_ANCHOR.MIDDLE)\n'
|
||
|
|
' self._text(slide, self.MX + 3.81, y_lbl + H_LBL + '
|
||
|
|
'GAP_LT,\n'
|
||
|
|
' self.SLIDE_W - 2 * self.MX - 5.33, H_TXT, '
|
||
|
|
'txt,\n'
|
||
|
|
' size=self.T["body"], color=self.C["body"],'
|
||
|
|
'\n'
|
||
|
|
' anchor=MSO_ANCHOR.MIDDLE)\n',
|
||
|
|
),
|
||
|
|
]
|
||
|
|
|
||
|
|
MARKER = "Hauteur réelle du bloc (C3b)"
|
||
|
|
|
||
|
|
|
||
|
|
def fail(msg):
|
||
|
|
print(" ! %s" % msg)
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
if not TARGET.exists():
|
||
|
|
fail("%s introuvable — lancer depuis le dossier du pipeline."
|
||
|
|
% TARGET)
|
||
|
|
content = TARGET.read_text(encoding="utf-8")
|
||
|
|
if MARKER in content:
|
||
|
|
fail("Déjà patché (C3b présent) — rien à faire.")
|
||
|
|
|
||
|
|
for i, (old, _) in enumerate(PATCHES, 1):
|
||
|
|
n = content.count(old)
|
||
|
|
if n == 0:
|
||
|
|
fail("Ancre du patch %d introuvable — moteur inattendu "
|
||
|
|
"(version différente ?)." % i)
|
||
|
|
if n > 1:
|
||
|
|
fail("Ancre du patch %d non unique (%d occurrences)." % (i, n))
|
||
|
|
|
||
|
|
shutil.copy2(TARGET, str(TARGET) + ".bak-c3b")
|
||
|
|
print(" + Sauvegarde : %s.bak-c3b" % TARGET)
|
||
|
|
|
||
|
|
for old, new in PATCHES:
|
||
|
|
content = content.replace(old, new)
|
||
|
|
|
||
|
|
TARGET.write_text(content, encoding="utf-8")
|
||
|
|
print(" + 2 patchs de centrage appliqués (big_stat, "
|
||
|
|
"executive_summary).")
|
||
|
|
try:
|
||
|
|
py_compile.compile(str(TARGET), doraise=True)
|
||
|
|
print(" + Compilation OK.")
|
||
|
|
except py_compile.PyCompileError as e:
|
||
|
|
shutil.copy2(str(TARGET) + ".bak-c3b", TARGET)
|
||
|
|
fail("Erreur de compilation — fichier restauré :\n%s" % e)
|
||
|
|
print("\n Re-rends et compare les previews : big_stat (chiffre "
|
||
|
|
"mieux centré),")
|
||
|
|
print(" executive_summary (texte centré dans les cartes). Vérifie "
|
||
|
|
"aussi from_to_pairs")
|
||
|
|
print(" (le rognage des labels a pu disparaître avec le fix polices "
|
||
|
|
"C3).")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|