from ..widgets.layout_capable_widgets import LAYOUT_CAPABLE_WIDGETS def _style_string(el, extra_base="", parent_flex_direction=None, widget_key=None): style = dict(el.get("style") or {}) if widget_key in LAYOUT_CAPABLE_WIDGETS and "display" not in style: # "Empilement libre" (valeur par défaut de "Disposition interne") # doit quand même permettre l'espacement (gap) entre les enfants — # or le CSS "gap" n'a aucun effet sur un display bloc classique, il # lui faut un conteneur flex/grid. Tant qu'aucune disposition n'a # été choisie explicitement, on bascule donc ce widget sur un flex # en colonne : visuellement identique à un simple empilement, mais # l'espacement fonctionne dès la création, sans avoir à changer la # disposition interne au préalable. style["display"] = "flex" style.setdefault("flex-direction", "column") is_child = bool(el.get("parent_id")) if is_child: # Élément physiquement posé à l'intérieur d'un conteneur/répéteur/ # groupe de champs : une hauteur fixée à 100% se calcule contre la # hauteur du parent et écraserait/déborderait les autres enfants # (le conteneur coupe alors ce qui dépasse -> l'enfant "disparaît"). # La hauteur s'adapte donc à son contenu, comme dans une vraie page. # Largeur : dans une disposition en LIGNE (flex-direction row), la # largeur est l'axe principal — si chaque enfant réclame 100% de # cette largeur, ils entrent en collision (l'algorithme flex les # comprime alors tous, jusqu'à les faire quasi disparaître). Dans les # autres cas (empilement libre, ou disposition en COLONNE où la # largeur est l'axe transversal), 100% reste le bon défaut. width_default = "auto" if parent_flex_direction in ("row", "row-reverse") else "100%" base_style = f"width:{width_default}; height:auto; box-sizing:border-box; margin:0;" + extra_base else: base_style = "width:100%; height:100%; box-sizing:border-box; margin:0;" + extra_base has_size_override = False def _emit(k, v): nonlocal has_size_override if v in (None, ""): return False if k == "transform" and not is_child: # Un élément posé directement sur un écran a déjà ce "transform" # posé sur son cadre .canvasElementInner / .playElementInner # (voir filters/element_style_filter.py:_element_transform_style) # — l'écrire ici aussi (sur la balise intérieure, à l'intérieur # d'un cadre qui reste fixe) donnait l'impression que l'échelle/ # l'animation restait "coincée à l'intérieur" au lieu de # s'appliquer à l'élément entier. Un élément posé à l'intérieur # d'un conteneur/répéteur/groupe de champs n'a pas ce cadre # séparé (sa balise EST déjà tout l'élément) : pour lui, # "transform" reste ici. return False if k in ("width", "height") and str(v).strip() in ("0px", "0"): # 0 = réglage "Taille dans le conteneur" laissé à sa valeur par # défaut (voir SIZE_OVERRIDE_CONTROLS) : ne pas l'écrire, pour # garder le comportement automatique de base_style ci-dessus. return False if k in ("width", "height"): has_size_override = True return True user_style = "; ".join(f"{k}:{v}" for k, v in style.items() if _emit(k, v)) if has_size_override: # Une taille fixe explicite (voir "Taille dans le conteneur") ne doit # pas être écrasée par la compression automatique d'une disposition # flex (flex-shrink vaut 1 par défaut sur tout enfant) — sinon un # élément à qui on a donné une largeur/hauteur précise peut quand # même se retrouver comprimé si ses voisins manquent de place. user_style = (user_style + "; " if user_style else "") + "flex-shrink:0" return base_style + (" " + user_style + ";" if user_style else "")