Files
Forge-Engine/screens/rendering/render_overlay.py
T
williamandClaude Sonnet 5 7c237d6f1c Retire le voile plein écran et le forçage de visibilité de l'éditeur (retour utilisateur)
Deux retours après le dernier correctif (78a373a, qui forçait
"display:flex" dans l'éditeur pour que la boîte de dialogue reste
visible) :
- "je souhaite avoir la main sur la visibilité de la modale sinon elle
  s'affiche toujours sur la scène, court-circuite ma logique" — le
  forçage empêchait de vraiment utiliser "Visibilité" pendant l'édition.
- "quand j'édite la modale ou quand je la mets dans une scène je
  souhaite que rien ne soit assombri, l'assombrissement ne se fait que
  quand la scène est jouée" — le voile plein écran (position:fixed +
  fond assombri) restait aussi actif dans l'éditeur.

Correctif (render_overlay.py) : le voile plein écran ET le forçage de
visibilité sont retirés de l'ÉDITEUR — ce widget s'y comporte maintenant
comme un CONTENEUR NORMAL (position/taille selon x/y/width/height, aucun
voile, réglage "Visibilité" respecté normalement, comme n'importe quel
autre widget masqué). Le comportement plein écran/voile/masquage par
défaut n'est conservé qu'en mode JOUABLE (ctx["_forge_play_mode"]).

En creusant pourquoi "Visible" ne suffisait pas à faire réapparaître la
boîte dans l'éditeur (menant l'utilisateur à essayer "Invisible" à la
place, visible dans ses captures), trouvé un vrai bug latent dans
save_element_controls.py : l'option "Visible" du réglage "Visibilité" ne
touche volontairement jamais "display" (pour ne pas écraser le
"display:flex" d'un conteneur en disposition ligne/colonne — voir
visibility_control.py) — ça fonctionne seulement parce que, pour un
widget AVEC un réglage "Disposition interne", celui-ci réaffirme lui-même
un display non-"none" au même enregistrement. La "superposition" n'a PAS
ce réglage : "display:none" (posé à la création ou par un "Masqué"
précédent) restait donc bloqué pour toujours, quel que soit le nombre de
fois où "Visible" était ensuite choisi. Corrigé : "Visible" efface aussi
"display" pour tout widget SANS réglage "Disposition interne" (safe : les
widgets qui EN ont un ne sont pas concernés, donc aucune régression sur
leur comportement existant).

Tests mis à jour (l'ancien test attendait le forçage, désormais retiré) +
nouveau test qui couvre le cycle complet (masqué par défaut -> "Visible"
choisi -> apparaît sans voile dans l'éditeur -> voile plein écran
retrouvé en mode jouable). 140 tests au vert au total.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 07:14:51 +02:00

101 lines
5.5 KiB
Python

import html as html_lib
from .visible_attrs import _visible_attrs
from .style_string import _style_string
from .render_children import _render_children
def _render_overlay(el, meta, slug, children_map=None, ctx=None, parent_flex_direction=None):
"""3.4 (Confort) — overlay/modale réutilisable : une boîte de dialogue
prête à l'emploi, par-dessus TOUT le reste de l'écran EN MODE JOUABLE
UNIQUEMENT (`position:fixed; inset:0` + voile semi-transparent, ignore
x/y/width/height) — fermeture manuelle uniquement (aucun
clic-en-dehors-pour-fermer volontairement, conformément au manque
documenté).
Dans l'ÉDITEUR (ctx sans "_forge_play_mode" — posé uniquement en mode
jouable, voir list_elements.py), ce widget se comporte comme un
CONTENEUR NORMAL : position/taille selon x/y/width/height comme
n'importe quel widget, respect normal de son réglage "Visibilité"
(masqué = invisible dans l'éditeur aussi, comme tout autre widget),
AUCUN voile plein écran. Deux essais précédents corrigés à partir des
retours utilisateur :
- Fond assombri visible pendant l'édition ("je veux que rien ne soit
assombri, l'assombrissement ne se fait que quand la scène est
jouée") : le voile (background:rgba(...)) ne fait donc plus partie
du style de base, il n'est ajouté qu'en mode jouable.
- Visibilité forcée en permanence dans l'éditeur ("je veux avoir la
main sur la visibilité, sinon elle s'affiche toujours sur la scène
et court-circuite ma logique") : le forçage display:flex a donc été
retiré — l'éditeur respecte de nouveau fidèlement le réglage
"Visibilité" (masqué par défaut à la création, pour ne plus couvrir
tout l'écran EN JEU dès qu'on la pose — sans plus aucun rapport avec
l'éditeur, qui ne couvre plus jamais rien).
Ouverture/fermeture (en JEU) : PAS de mécanisme dédié — elle réutilise
l'action existante "Modifier un élément → Visibilité" (masquer/rendre
visible), exactement comme n'importe quel autre élément.
Classes Bulma ("modal is-active" / "box") posées en PLUS du style
inline, jamais à sa place, et UNIQUEMENT en mode jouable (voir
ci-dessus) : tout le positionnement/masquage critique (position:fixed,
z-index, display) reste en inline, qui gagne toujours sur une règle de
classe — si Bulma (chargé depuis un CDN, voir play.html) ne se charge
pas (hors-ligne), la boîte de dialogue continue de fonctionner
exactement pareil. Pas de ".modal-background" séparé : le voile
semi-transparent est déjà posé en inline sur cette même balise
(background:rgba(...)) — un second calque tout aussi transparent
par-dessus n'ajouterait rien."""
is_play_mode = bool(ctx and ctx.get("_forge_play_mode"))
attrs_raw = el.get("attributes") or {}
box_color = attrs_raw.get("_couleur_boite") or "#1f2430"
radius = attrs_raw.get("_arrondi") or "12"
attrs = _visible_attrs(el, meta, ctx)
if is_play_mode:
base_overlay_style = (
"position:fixed; inset:0; z-index:9999; display:flex; "
"align-items:center; justify-content:center; background:rgba(0,0,0,0.6);"
)
style = base_overlay_style + " " + _style_string(el, parent_flex_direction=parent_flex_direction)
wrapper_class = "modal is-active"
else:
style = _style_string(el, parent_flex_direction=parent_flex_direction)
wrapper_class = ""
attr_parts = [f'style="{html_lib.escape(style)}"']
for k, v in attrs.items():
if v in (None, "", False):
continue
attr_parts.append(
html_lib.escape(str(k)) if v is True else f'{html_lib.escape(str(k))}="{html_lib.escape(str(v))}"'
)
box_style = (
f"background:{html_lib.escape(str(box_color))}; border-radius:{html_lib.escape(str(radius))}px; "
# max-width en min(...) plutôt qu'un simple pourcentage : sur un
# écran de jeu large (desktop), "90%" seul donnait une boîte étirée
# bord à bord peu lisible comme dialogue — 560px reste une largeur
# de boîte de dialogue confortable, tout en retombant sur 90% sur un
# écran de jeu étroit (mobile/portrait) pour ne jamais déborder.
# color:#e8eaf0 : la classe Bulma ".box" (ajoutée ci-dessous) impose
# elle-même une couleur de texte SOMBRE (pensée pour un fond blanc
# par défaut) — comme aucun widget ne fige de couleur de texte à sa
# création (default_style_for_widget.py), un titre/texte posé dans
# la boîte SANS couleur personnalisée héritait de ce gris sombre
# imposé par Bulma, invisible sur le fond sombre par défaut de cette
# boîte de dialogue (texte "présent mais invisible", pas de bug côté
# utilisateur). On redonne donc ici une couleur claire par défaut,
# que Bulma ne peut plus écraser (élément le plus proche gagne) —
# un texte/titre qui personnalise sa propre couleur reste bien sûr
# prioritaire sur celle-ci.
"color:#e8eaf0; padding:24px; width:100%; max-width:min(560px, 90%); max-height:90%; overflow:auto; box-sizing:border-box;"
)
child_html = _render_children(el, slug, children_map, ctx)
wrapper_class_attr = f'class="{wrapper_class}" ' if wrapper_class else ""
return (
f'<div {wrapper_class_attr}{" ".join(attr_parts)}>'
f'<div class="box forgeOverlayBox" style="{html_lib.escape(box_style)}">{child_html}</div>'
f"</div>"
)