L'utilisateur a testé la Phase 7 (sprites pilotés via un menu déroulant + zone de texte dans la logique de flow) et l'a rejetée à raison : ce n'est pas comme ça qu'un moteur de jeu (Phaser, Unity) gère un personnage. Cette refonte remplace tout le flux d'AUTEURING par un vrai widget visuel — le moteur d'exécution de la Phase 7 (runSpriteAnimation, activeSpriteAnimations, orientation, kind="sprite" de la Timeline) reste inchangé. Nouveau widget "personnage" (screens/widgets/registry.py) : - Rendu serveur dédié (special_render, screens/rendering/render_personnage.py) qui affiche la pose "idle" dès le HTML généré — jamais une image cassée à configurer après coup. - Toutes ses données (source Forge ou sprites propres au créateur, quel personnage/quelles animations) vivent dans une seule clé JSON _personnage_data (screens/rendering/personnage_data.py), sans aucune migration de schéma (même patron que c_clause_list). - Nouvelle échappatoire "custom_panel", symétrique à "special_render" mais pour le panneau de propriétés : ce widget affiche une galerie/un import de sprites sur-mesure plutôt que les contrôles génériques. Galerie visuelle de personnages Forge (VRAIES miniatures, pas un emoji) : - Panneau gauche "🎭 Personnages" : pose un personnage déjà configuré, animé immédiatement. - Panneau droit (propriétés) : change le personnage Forge de l'élément sélectionné, ou importe les animations d'un sprite personnalisé. - static/js/screen_edit/personnage-preview.js : lance l'aperçu animé de CHAQUE personnage du canevas dès le chargement de la page et après toute sauvegarde — le cœur de la demande ("je dois voir ça bouger"). Sélecteur d'animation à miniatures (nœud de flow "Jouer une animation" et clip de Timeline "sprite") : remplace le menu déroulant/la zone de texte par une grille de vraies miniatures, scopée aux SEULES animations du personnage réellement ciblé (ELEMENT_ANIMATIONS_MAP, résolu côté serveur à partir des propriétés de cet élément précis) — jamais un catalogue global. Le format stocké sur le nœud/le clip ({frames, fps, loop}) est inchangé, seule l'UI d'édition change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
354 lines
24 KiB
Python
354 lines
24 KiB
Python
from .controls.c_text import c_text
|
||
from .controls.c_textarea import c_textarea
|
||
from .controls.c_url import c_url
|
||
from .controls.c_color import c_color
|
||
from .controls.c_slider import c_slider
|
||
from .controls.c_checkbox import c_checkbox
|
||
from .controls.c_toggle_token import c_toggle_token
|
||
from .controls.c_align import c_align
|
||
from .controls.c_select import c_select
|
||
from .control_groups.text_style_controls_extra import TEXT_STYLE_CONTROLS_EXTRA
|
||
from .control_groups.data_binding_controls import DATA_BINDING_CONTROLS
|
||
from .control_groups.bulma_controls import (
|
||
BULMA_BUTTON_CONTROLS, BULMA_TITLE_CONTROLS, BULMA_PROGRESS_CONTROLS,
|
||
BULMA_TABLE_CONTROLS, BULMA_TABS_CONTROLS, BULMA_FIELD_CONTROLS,
|
||
)
|
||
from .font_options import FONT_OPTIONS
|
||
from ..flow.constants import CONDITION_OPERATORS
|
||
|
||
WIDGETS = {
|
||
"texte": {
|
||
"label": "Texte", "icon": "📝", "tag": "p", "has_content": True,
|
||
"w": 40, "h": 10, "default_content": "Texte du paragraphe.",
|
||
"controls": [
|
||
c_textarea("content", "Texte — {{champ}} affiche la valeur de ce champ sur la ligne trouvée ci-dessous", "content", default="Texte du paragraphe.", group="Contenu"),
|
||
] + DATA_BINDING_CONTROLS + [
|
||
c_slider("font-size", "Taille du texte", "style:font-size", min=10, max=64, default=16, group="Texte"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
c_align("text-align", "Alignement", "style:text-align", group="Texte"),
|
||
c_checkbox("bold", "Gras", "style:font-weight", "bold", "normal", group="Texte"),
|
||
c_checkbox("italic", "Italique", "style:font-style", "italic", "normal", group="Texte"),
|
||
c_toggle_token("underline", "Souligné", "style:text-decoration", "underline", group="Texte"),
|
||
c_toggle_token("strikethrough", "Barré", "style:text-decoration", "line-through", group="Texte"),
|
||
] + TEXT_STYLE_CONTROLS_EXTRA,
|
||
},
|
||
"titre": {
|
||
"label": "Titre", "icon": "🔠", "tag": None, "has_content": True,
|
||
"w": 55, "h": 10, "default_content": "Titre",
|
||
# class:"title" — poids de police et espacement Bulma par défaut ; la
|
||
# taille reste pilotée par le réglage "Taille du texte" ci-dessous
|
||
# comme avant (non affecté), Bulma ne fournissant ici que l'habillage.
|
||
"fixed_attrs": {"class": "title"},
|
||
"controls": [
|
||
c_textarea("content", "Texte — {{champ}} affiche la valeur de ce champ sur la ligne trouvée ci-dessous", "content", default="Titre", group="Contenu"),
|
||
c_select("niveau", "Importance du titre", "attr:_niveau",
|
||
[("1", "Très grand — titre principal"), ("2", "Grand"), ("3", "Moyen")], default="2", group="Contenu"),
|
||
] + DATA_BINDING_CONTROLS + BULMA_TITLE_CONTROLS + [
|
||
c_slider("font-size", "Taille du texte", "style:font-size", min=14, max=80, default=32, group="Texte"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
c_align("text-align", "Alignement", "style:text-align", default="left", group="Texte"),
|
||
c_checkbox("italic", "Italique", "style:font-style", "italic", "normal", group="Texte"),
|
||
c_toggle_token("underline", "Souligné", "style:text-decoration", "underline", group="Texte"),
|
||
] + TEXT_STYLE_CONTROLS_EXTRA,
|
||
},
|
||
"bouton": {
|
||
"label": "Bouton", "icon": "🔘", "tag": "button", "has_content": True,
|
||
"w": 30, "h": 8, "default_content": "Valider",
|
||
# class:"button" — donne au Bouton l'apparence Bulma par défaut
|
||
# (padding, poids de police, transitions...) tant qu'aucune couleur/
|
||
# taille "libre" n'est personnalisée ci-dessous — voir
|
||
# BULMA_BUTTON_CONTROLS et _visible_attrs.py.
|
||
"fixed_attrs": {"class": "button"},
|
||
"controls": [
|
||
c_text("content", "Texte du bouton", "content", default="Valider", group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#ffffff", group="Texte"),
|
||
c_color("background", "Couleur de fond", "style:background-color", "#5b8cff", group="Texte"),
|
||
c_slider("font-size", "Taille du texte", "style:font-size", min=10, max=40, default=15, group="Texte", no_freeze=True),
|
||
c_slider("border-radius", "Arrondi des coins", "style:border-radius", min=0, max=40, default=8, group="Texte", no_freeze=True),
|
||
c_checkbox("submit", "Valide un formulaire", "attr:type", "submit", "button", group="Contenu"),
|
||
] + BULMA_BUTTON_CONTROLS + TEXT_STYLE_CONTROLS_EXTRA,
|
||
},
|
||
"lien": {
|
||
"label": "Lien", "icon": "🔗", "tag": "a", "has_content": True,
|
||
"w": 25, "h": 6, "default_content": "Cliquez ici",
|
||
"controls": [
|
||
c_text("content", "Texte du lien", "content", default="Cliquez ici", group="Contenu"),
|
||
c_url("href", "Destination", "attr:href", default="#", group="Contenu"),
|
||
c_checkbox("new_tab", "Ouvrir dans un nouvel onglet", "attr:target", "_blank", "", group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#5b8cff", group="Texte"),
|
||
c_toggle_token("underline", "Souligné", "style:text-decoration", "underline", group="Texte"),
|
||
] + TEXT_STYLE_CONTROLS_EXTRA,
|
||
},
|
||
"image": {
|
||
"label": "Image", "icon": "🖼️", "tag": "img", "has_content": False, "self_closing": True,
|
||
"w": 35, "h": 22, "default_content": "",
|
||
"controls": [
|
||
c_url("src", "Source de l'image", "attr:src", allow_upload=True, upload_accept="image/*", group="Contenu"),
|
||
c_text("alt", "Texte alternatif", "attr:alt", placeholder="décrit l'image pour l'accessibilité", group="Contenu"),
|
||
c_select("object-fit", "Ajustement dans son cadre", "style:object-fit",
|
||
[("cover", "Remplir en recadrant"), ("contain", "Tout montrer sans déformer"), ("fill", "Étirer pour remplir tout le cadre")],
|
||
default="cover", group="Média"),
|
||
c_slider("border-radius", "Arrondi des coins", "style:border-radius", min=0, max=60, default=0, group="Média"),
|
||
],
|
||
},
|
||
"video": {
|
||
"label": "Vidéo", "icon": "🎬", "tag": "video", "has_content": False,
|
||
"w": 40, "h": 25, "default_content": "",
|
||
"controls": [
|
||
c_url("src", "Source de la vidéo", "attr:src", allow_upload=True, upload_accept="video/*", group="Contenu"),
|
||
c_checkbox("controls", "Afficher les contrôles de lecture", "attr:controls", "controls", "", default=True, group="Contenu"),
|
||
c_checkbox("autoplay", "Lecture automatique", "attr:autoplay", "autoplay", "", group="Contenu"),
|
||
c_checkbox("loop", "Lecture en boucle", "attr:loop", "loop", "", group="Contenu"),
|
||
],
|
||
},
|
||
"champ_texte": {
|
||
"label": "Champ — texte", "icon": "⌨️", "tag": "input", "has_content": False, "self_closing": True,
|
||
"w": 40, "h": 8, "default_content": "", "fixed_attrs": {"type": "text", "class": "input"},
|
||
"controls": [
|
||
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. Votre réponse", group="Contenu"),
|
||
c_text("name", "Nom du champ", "attr:name", placeholder="ex. reponse1", group="Contenu"),
|
||
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
|
||
] + BULMA_FIELD_CONTROLS,
|
||
},
|
||
"champ_email": {
|
||
"label": "Champ — email", "icon": "📧", "tag": "input", "has_content": False, "self_closing": True,
|
||
"w": 40, "h": 8, "default_content": "", "fixed_attrs": {"type": "email", "class": "input"},
|
||
"controls": [
|
||
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. votre@email.com", default="votre@email.com", group="Contenu"),
|
||
c_text("name", "Nom du champ", "attr:name", placeholder="ex. email", group="Contenu"),
|
||
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
|
||
] + BULMA_FIELD_CONTROLS,
|
||
},
|
||
"champ_mot_de_passe": {
|
||
"label": "Champ — mot de passe", "icon": "🔒", "tag": "input", "has_content": False, "self_closing": True,
|
||
"w": 40, "h": 8, "default_content": "", "fixed_attrs": {"type": "password", "class": "input"},
|
||
"controls": [
|
||
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. Mot de passe", group="Contenu"),
|
||
c_text("name", "Nom du champ", "attr:name", placeholder="ex. mot_de_passe", group="Contenu"),
|
||
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
|
||
] + BULMA_FIELD_CONTROLS,
|
||
},
|
||
"case_a_cocher": {
|
||
"label": "Case à cocher", "icon": "☑️", "tag": "input", "has_content": True, "special_render": "checkbox_label",
|
||
"w": 35, "h": 8, "default_content": "Option",
|
||
"controls": [
|
||
c_text("content", "Texte affiché", "content", default="Option", group="Contenu"),
|
||
c_text("name", "Nom du champ", "attr:name", placeholder="ex. accepte_cgu", group="Contenu"),
|
||
c_text("value", "Valeur envoyée", "attr:value", placeholder="ex. oui", group="Contenu"),
|
||
c_checkbox("checked", "Coché par défaut", "attr:checked", "checked", "", group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
],
|
||
},
|
||
"bouton_radio": {
|
||
"label": "Bouton radio", "icon": "🔘", "tag": "input", "has_content": True, "special_render": "checkbox_label",
|
||
"w": 35, "h": 8, "default_content": "Option",
|
||
"controls": [
|
||
c_text("content", "Texte affiché", "content", default="Option", group="Contenu"),
|
||
c_text("name", "Nom du groupe", "attr:name", placeholder="ex. choix1", group="Contenu"),
|
||
c_text("value", "Valeur envoyée", "attr:value", placeholder="ex. optionA", group="Contenu"),
|
||
c_checkbox("checked", "Sélectionné par défaut", "attr:checked", "checked", "", group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
],
|
||
},
|
||
"zone_texte": {
|
||
"label": "Zone de texte", "icon": "🗒️", "tag": "textarea", "has_content": False,
|
||
"w": 40, "h": 18, "default_content": "", "fixed_attrs": {"class": "textarea"},
|
||
"controls": [
|
||
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. Votre message", group="Contenu"),
|
||
c_text("name", "Nom du champ", "attr:name", placeholder="ex. message", group="Contenu"),
|
||
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
|
||
] + BULMA_FIELD_CONTROLS,
|
||
},
|
||
"liste_deroulante": {
|
||
"label": "Liste déroulante", "icon": "🔽", "tag": "select", "has_content": True, "special_render": "select_options",
|
||
"w": 35, "h": 8, "default_content": "Option 1\nOption 2\nOption 3",
|
||
"controls": [
|
||
c_textarea("content", "Options — une par ligne", "content", default="Option 1\nOption 2\nOption 3", group="Contenu"),
|
||
c_text("name", "Nom du champ", "attr:name", placeholder="ex. choix", group="Contenu"),
|
||
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
|
||
] + BULMA_FIELD_CONTROLS,
|
||
},
|
||
"groupe_champs": {
|
||
"label": "Groupe de champs", "icon": "🗃️", "tag": "fieldset", "has_content": True, "special_render": "fieldset_legend",
|
||
"w": 55, "h": 30, "default_content": "Groupe de champs",
|
||
"controls": [
|
||
c_text("content", "Titre du groupe", "content", default="Groupe de champs", group="Contenu"),
|
||
],
|
||
},
|
||
"liste": {
|
||
"label": "Liste à puces", "icon": "📋", "tag": "ul", "has_content": True,
|
||
"w": 40, "h": 22, "default_content": "Premier élément\nDeuxième élément\nTroisième élément",
|
||
"controls": [
|
||
c_textarea("content", "Éléments de la liste — un par ligne", "content",
|
||
default="Premier élément\nDeuxième élément\nTroisième élément", group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
c_slider("font-size", "Taille du texte", "style:font-size", min=10, max=40, default=16, group="Texte"),
|
||
],
|
||
},
|
||
"liste_numerotee": {
|
||
"label": "Liste numérotée", "icon": "🔢", "tag": "ol", "has_content": True,
|
||
"w": 40, "h": 22, "default_content": "Premier élément\nDeuxième élément\nTroisième élément",
|
||
"controls": [
|
||
c_textarea("content", "Éléments de la liste — un par ligne", "content",
|
||
default="Premier élément\nDeuxième élément\nTroisième élément", group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
c_slider("font-size", "Taille du texte", "style:font-size", min=10, max=40, default=16, group="Texte"),
|
||
],
|
||
},
|
||
"tableau": {
|
||
"label": "Tableau", "icon": "🗂️", "tag": "table", "has_content": True, "special_render": "table",
|
||
"w": 55, "h": 25, "default_content": "Colonne 1;Colonne 2\nValeur A;Valeur B",
|
||
"fixed_attrs": {"class": "table"},
|
||
"controls": [
|
||
c_textarea("content", "Contenu — une ligne par rangée, colonnes séparées par ;", "content",
|
||
default="Colonne 1;Colonne 2\nValeur A;Valeur B", group="Contenu"),
|
||
c_checkbox("header_row", "Première ligne = en-tête", "attr:_header_row", "1", "", default=True, group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
] + BULMA_TABLE_CONTROLS,
|
||
},
|
||
"conteneur": {
|
||
"label": "Conteneur / décor", "icon": "⬛", "tag": "div", "has_content": True,
|
||
"w": 50, "h": 30, "default_content": "",
|
||
# class:"box" — ce widget EST une carte Bulma nativement (fond clair,
|
||
# ombre, coins arrondis), pas un habillage qu'on choisit dans un
|
||
# menu : voir bouton/titre ci-dessus, même logique. Une couleur de
|
||
# fond personnalisée (réglage ci-dessous) reste prioritaire dès
|
||
# qu'elle est choisie, exactement comme avant.
|
||
"fixed_attrs": {"class": "box"},
|
||
"controls": [
|
||
c_text("content", "Texte", "content", group="Contenu"),
|
||
c_color("background", "Couleur de fond", "style:background-color", "#1f2430", group="Texte"),
|
||
c_slider("border-radius", "Arrondi des coins", "style:border-radius", min=0, max=60, default=10, group="Texte", no_freeze=True),
|
||
c_slider("opacity", "Opacité", "style:opacity", unit="", min=0, max=1, step=0.05, default=1, group="Texte"),
|
||
],
|
||
},
|
||
"separateur": {
|
||
"label": "Séparateur", "icon": "➖", "tag": "hr", "has_content": False, "self_closing": True,
|
||
"w": 50, "h": 2, "default_content": "",
|
||
"controls": [
|
||
c_color("color", "Couleur", "style:border-color", "#2b3140", group="Texte"),
|
||
],
|
||
},
|
||
"repeteur_donnees": {
|
||
"label": "Répéteur de données", "icon": "🔁", "tag": "div", "has_content": True, "special_render": "repeater",
|
||
"w": 55, "h": 35, "default_content": "{{nom}}",
|
||
"controls": [
|
||
c_select("definition_id", "Objet de données à afficher", "attr:_definition_id",
|
||
[("", "Sélectionner un objet")], default="", group="Contenu"),
|
||
c_select("template_type_id", "Modèle de ligne — élément de jeu", "attr:_template_type_id",
|
||
[("", "Aucun — utiliser le modèle de texte ci-dessous")], default="", group="Contenu"),
|
||
c_textarea("content", "Modèle d'affichage texte — utilise {{nom_du_champ}}", "content", default="{{nom}}", group="Contenu"),
|
||
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
|
||
c_slider("font-size", "Taille du texte", "style:font-size", min=10, max=40, default=16, group="Texte"),
|
||
c_select("filtre_champ", "Filtrer : n'afficher que les lignes où ce champ",
|
||
"attr:_filtre_champ", [("", "(sélectionner un objet d'abord)")], default="", group="Filtre"),
|
||
c_select("filtre_operateur", "...est", "attr:_filtre_operateur", CONDITION_OPERATORS, default="egal", group="Filtre"),
|
||
c_text("filtre_valeur", "...cette valeur",
|
||
"attr:_filtre_valeur", placeholder="ex. 3", default="", group="Filtre"),
|
||
c_select("filtre2_champ", "ET (optionnel) : ce 2ᵉ champ",
|
||
"attr:_filtre2_champ", [("", "(sélectionner un objet d'abord)")], default="", group="Filtre"),
|
||
c_select("filtre2_operateur", "...est", "attr:_filtre2_operateur", CONDITION_OPERATORS, default="egal", group="Filtre"),
|
||
c_text("filtre2_valeur", "...cette valeur",
|
||
"attr:_filtre2_valeur", placeholder="ex. 1", default="", group="Filtre"),
|
||
],
|
||
},
|
||
"jauge": {
|
||
"label": "Jauge — liée à une donnée", "icon": "📊", "tag": "div", "has_content": False, "special_render": "jauge",
|
||
"w": 60, "h": 12, "default_content": "",
|
||
"controls": [
|
||
# La clé "definition_id" est reconnue spécifiquement dans
|
||
# controls_with_values.py pour être peuplée avec les VRAIS
|
||
# objets de données du jeu — même mécanisme que le Répéteur.
|
||
c_select("definition_id", "Objet de données à suivre", "attr:_definition_id",
|
||
[("", "Sélectionner un objet")], default="", group="Donnée"),
|
||
# row_id/champ/champ_nom : options peuplées dynamiquement une
|
||
# fois "definition_id" choisi — voir controls_with_values.py
|
||
# (premier affichage) et onJaugeDefinitionChange() dans
|
||
# screen_edit.html (changement en direct dans le panneau).
|
||
c_select("row_id", "Enregistrement (ligne) à suivre", "attr:_row_id",
|
||
[("", "Sélectionner un objet d'abord")], default="", group="Donnée"),
|
||
c_select("champ", "Champ numérique à afficher", "attr:_champ",
|
||
[("", "Sélectionner un objet d'abord")], default="", group="Donnée"),
|
||
c_select("champ_nom", "Champ contenant le nom (affiché au-dessus, optionnel)", "attr:_champ_nom",
|
||
[("", "— aucun —")], default="", group="Donnée"),
|
||
c_text("min", "Valeur mini", "attr:_min", default="0", group="Donnée"),
|
||
c_text("max", "Valeur maxi", "attr:_max", default="100", group="Donnée"),
|
||
c_color("couleur_basse", "Couleur côté mini", "attr:_couleur_basse", "#e05252", group="Apparence"),
|
||
c_color("couleur_haute", "Couleur côté maxi", "attr:_couleur_haute", "#4caf50", group="Apparence"),
|
||
c_checkbox("afficher_valeur", "Afficher la valeur en chiffres sur la jauge", "attr:_afficher_valeur", "1", "", default=False, group="Apparence"),
|
||
c_select("nom_position", "Position du nom", "attr:_nom_position",
|
||
[("dessus", "Au-dessus de la jauge"), ("cote", "À côté (à gauche) de la jauge")],
|
||
default="dessus", group="Apparence"),
|
||
c_select("nom_alignement", "Alignement du nom (si au-dessus)", "attr:_nom_alignement",
|
||
[("centre", "Centré"), ("gauche", "Aligné à gauche")],
|
||
default="centre", group="Apparence"),
|
||
c_select("nom_police", "Police du nom", "attr:_nom_police", FONT_OPTIONS, default="inherit", group="Apparence"),
|
||
c_slider("nom_taille", "Taille du texte du nom", "attr:_nom_taille", unit="", min=8, max=32, default=12, group="Apparence"),
|
||
c_checkbox("nom_gras", "Nom en gras", "attr:_nom_gras", "1", "", default=False, group="Apparence"),
|
||
c_checkbox("nom_italique", "Nom en italique", "attr:_nom_italique", "1", "", default=False, group="Apparence"),
|
||
] + BULMA_PROGRESS_CONTROLS,
|
||
},
|
||
"superposition": {
|
||
# 3.4 (Confort) — overlay/modale réutilisable : couvre TOUJOURS tout
|
||
# l'écran (position:fixed, indépendant de x/y/width/height — voir
|
||
# render_overlay.py), avec un voile semi-transparent + une boîte
|
||
# centrée qui contient les éléments posés à l'intérieur. Fermeture
|
||
# manuelle uniquement : réutilise l'action existante "Modifier un
|
||
# élément → Visibilité" (masquer/rendre visible), comme n'importe
|
||
# quel autre élément — pas de mécanisme de fermeture au clic externe.
|
||
"label": "Superposition / boîte de dialogue", "icon": "🪟", "tag": "div", "has_content": True,
|
||
"special_render": "overlay",
|
||
"w": 50, "h": 40, "default_content": "",
|
||
"controls": [
|
||
c_text("content", "Texte — en plus des éléments posés dans la boîte", "content", group="Contenu"),
|
||
c_color("couleur_boite", "Couleur de fond de la boîte", "attr:_couleur_boite", "#1f2430", group="Apparence"),
|
||
c_slider("arrondi", "Arrondi des coins de la boîte", "attr:_arrondi", unit="", min=0, max=40, default=12, group="Apparence"),
|
||
],
|
||
},
|
||
"onglets": {
|
||
# Chaque onglet est un vrai élément "conteneur" posé comme enfant
|
||
# (voir screens/elements/add_tab.py et render_onglets.py) — pas de
|
||
# gestion dédiée ici : ajouter/renommer/supprimer un onglet se fait
|
||
# via le bloc "Onglets" du panneau de propriétés (screen_edit.html),
|
||
# qui réutilise les routes existantes (element_rename, element_delete).
|
||
"label": "Onglets", "icon": "🗂️", "tag": "div", "has_content": False, "special_render": "onglets",
|
||
"w": 60, "h": 40, "default_content": "",
|
||
"controls": BULMA_TABS_CONTROLS,
|
||
},
|
||
"personnage": {
|
||
# Widget Personnage (Phase 8) — un vrai objet visuel, pas une image
|
||
# générique pilotée depuis la logique de flow (voir le plan :
|
||
# l'utilisateur a explicitement rejeté ce premier design). Toutes ses
|
||
# données (source Forge/personnalisée, animations) vivent dans UNE
|
||
# clé JSON _personnage_data (voir screens/rendering/personnage_data.py
|
||
# et screens/elements/set_personnage_data.py) — pas de contrôle
|
||
# générique ici, "custom_panel" bascule le panneau de propriétés vers
|
||
# un bloc entièrement sur-mesure (galerie Forge ou import de sprites,
|
||
# voir templates/screen_edit.html et static/js/screen_edit/
|
||
# personnage-panel.js), la taille/position restant les réglages
|
||
# universels déjà là pour tout élément.
|
||
"label": "Personnage", "icon": "🏃", "tag": "img", "has_content": False, "self_closing": True,
|
||
"special_render": "personnage", "custom_panel": "personnage",
|
||
"w": 20, "h": 30, "default_content": "",
|
||
"controls": [],
|
||
},
|
||
"icone": {
|
||
# Un SVG affiché en silhouette via "mask-image" (voir .icon-svg dans
|
||
# style.css et render_icone.py) plutôt qu'une police d'icônes —
|
||
# certains navigateurs/extensions bloquent le chargement de polices
|
||
# web tierces (protection anti-fingerprinting), ce qui rendait
|
||
# invisible toute icône Font Awesome classique quelle que soit sa
|
||
# source (CDN ou même hébergée ici). Le nom de l'icône (ex. "star")
|
||
# est posé soit en cliquant/glissant depuis la galerie du panneau de
|
||
# propriétés (voir routes/elements/element_add.py), soit choisi via
|
||
# le sélecteur visuel du réglage "Icône" — jamais tapé à la main.
|
||
"label": "Icône", "icon": "🔤", "tag": "i", "has_content": False, "special_render": "icone",
|
||
"w": 15, "h": 15, "default_content": "",
|
||
"controls": [
|
||
c_text("icon_class", "Icône", "attr:_icon_slug", default="star", group="Contenu"),
|
||
c_slider("font-size", "Taille", "style:font-size", min=10, max=160, default=32, group="Texte"),
|
||
c_color("color", "Couleur", "style:color", "#e8eaf0", group="Texte"),
|
||
],
|
||
},
|
||
}
|