Files
Forge-Engine/screens/__init__.py
T
williamandClaude Sonnet 5 92fbfbc9dd
Build and deploy / test-python (push) Successful in 1m26s
Build and deploy / test-js (push) Successful in 7s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Phase 4 : ajout dynamique d'une ligne à l'exécution
Nouveau sentinel LAST_INSERTED_ROW_ID = -3 (screens/flow/constants.py),
aux côtés de CLICKED_ROW_ID = -1 — même principe : un id de ligne
n'existe qu'APRÈS l'insertion, jamais connu à la création du nœud.
Permet d'enchaîner un nœud "Ajouter une ligne" (crée une ligne VIDE) puis
un ou plusieurs nœuds "Modifier une donnée" déjà existants (ciblant
"➕ Dernière ligne ajoutée" dans le sélecteur "Ligne concernée", partagé
avec les conditions) pour renseigner ses champs — réutilise 100% du
mécanisme actuel, aucun nouveau format de payload multi-champs.

screens/data_actions/apply_add_row_action.py : db.get_definition +
db.insert_row(slug, definition, {}, player_id) — la ligne appartient au
joueur qui agit pour un objet per_player (Phase 1).

Nouvelles routes (créateur ET publique, comme prévu dès la Phase 1) :
POST /game/<slug>/flow/nodes/<id>/run-add-row et son miroir
/jouer/<slug>/.../run-add-row — renvoient {"ok", "row_id"}.
routes/flow/flow_node_run_data.py (+ son miroir public) : résout aussi
LAST_INSERTED_ROW_ID (en plus de CLICKED_ROW_ID déjà en place) via
last_inserted_row_id transmis par le client.

static/js/play/actions.js : runActionNode branche "ajouter_ligne" ->
fetch la nouvelle route, pose window.lastInsertedRowId, puis
refreshRuntimeData() (un Répéteur lié affiche la nouvelle ligne au
prochain rendu, confirmé par l'audit préalable — aucun ajustement du
mécanisme de rafraîchissement nécessaire). La branche "modifier_donnee"
transmet désormais aussi last_inserted_row_id, comme clicked_row_id.

templates/screen_edit.html + static/js/screen_edit/flow-editor.js :
nouveau type d'action "Ajouter une ligne à un objet" (juste un
sélecteur d'objet, aucun champ à remplir — le rappel du fonctionnement
enchaîné est affiché directement dans le formulaire) ; le sélecteur
"Ligne concernée" (partagé Condition/Modifier une donnée) gagne l'option
"➕ Dernière ligne ajoutée" à côté de "🖱️ Ligne cliquée".

Vérifié : 259 tests passent (4 nouveaux, dont un bout-en-bout via HTTP
qui enchaîne réellement les deux nœuds et vérifie le champ renseigné, et
un qui verrouille l'isolation par joueur de la ligne créée), 13 tests
node:test toujours au vert, syntaxe JS validée.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 17:18:10 +02:00

134 lines
6.8 KiB
Python

"""
screens.py — écrans de jeu : éléments posés en glisser-déposer sur un
écran, sans jamais toucher à un fichier HTML/CSS, enchaînement des écrans,
et actions déclenchées par clic ou soumission de formulaire.
Version 3 — inspirée d'Elementor / Bricks Builder : un catalogue fermé de
WIDGETS (Texte, Titre, Image, Bouton, Case à cocher, Répéteur de
données...), chacun avec ses propres réglages ("controls") : un réglage =
un champ, une case à cocher, un bouton radio ou un curseur — jamais de nom
de balise ni de nom de propriété CSS à taper. En coulisses, chaque widget
correspond à une vraie balise HTML avec de vrais attributs et un vrai
style CSS ; l'utilisateur ne les manipule jamais directement.
Tout est stocké dans la même base SQLite que le reste du jeu
(projects/<slug>/game.db) :
- _screens : un écran du jeu (accueil, formulaire, scène...)
- _element_types : le "catalogue" des éléments de jeu réutilisables
(Personnage, Outil, IA...) que l'utilisateur crée
- _screen_elements : chaque élément posé sur un écran (widget, position
et taille en POURCENTAGE de l'écran, contenu,
attributs et style — dérivés des réglages du
widget, jamais saisis en texte libre)
- _actions : ce qui se passe au clic / à la soumission d'un
élément (écran suivant, écran précédent, aller à
un écran précis, ne rien faire)
Un élément peut aussi être un "Répéteur de données" : au lieu d'un contenu
fixe, il est relié à un objet défini dans ce jeu (voir db.py) et affiche
automatiquement une ligne par donnée existante — par exemple, tous les
niveaux d'un parcours — à partir d'un modèle de texte avec des
{{nom_de_champ}}.
Ce fichier est désormais un package (voir les sous-dossiers) organisé
selon "un fichier = une fonction, un dossier = une responsabilité" ; ce
module se contente de ré-exporter l'intégralité de l'API publique
utilisée par app.py et les templates, afin que `import screens` continue
de fonctionner à l'identique.
"""
from .widgets.registry import WIDGETS
from .widgets.container_widgets import CONTAINER_WIDGETS
from .widgets.layout_capable_widgets import LAYOUT_CAPABLE_WIDGETS
from .widgets.fontawesome_icons import FONTAWESOME_ICONS
from .widgets.widget_meta import widget_meta
from .widgets.controls_with_values import controls_with_values
from .widgets.data_definition_options import data_definition_options
from .labels.trigger_labels import TRIGGER_LABELS
from .labels.action_type_labels import ACTION_TYPE_LABELS
from .labels.element_action_properties import (
ELEMENT_ACTION_PROPERTIES, ELEMENT_ACTION_PROPERTY_LABELS,
ELEMENT_SURBRILLANCE_VALUES, ELEMENT_SURBRILLANCE_LABELS,
ELEMENT_DESACTIVE_VALUES, ELEMENT_DESACTIVE_LABELS,
)
from .labels.element_visibility import ELEMENT_VISIBILITY_VALUES, ELEMENT_VISIBILITY_LABELS
from .labels.data_operations import DATA_OPERATIONS, DATA_OPERATION_LABELS
from .flow.constants import (
TRIGGER_EVENTS, CONDITION_OPERATORS, CONDITION_OPERATOR_LABELS, CLICKED_ROW_ID, LAST_INSERTED_ROW_ID,
)
from .rendering.render_element_html import render_element_html
from .rendering.trigger_for import _trigger_for
from .screens_repo.ensure_schema import ensure_schema
from .screens_repo.list_screens import list_screens
from .screens_repo.get_screen import get_screen
from .screens_repo.create_screen import create_screen
from .screens_repo.rename_screen import rename_screen
from .screens_repo.delete_screen import delete_screen
from .screens_repo.move_screen import move_screen
from .screens_repo.screens_referencing import screens_referencing
from .screens_repo.set_screen_aspect import set_screen_aspect
from .elements.list_elements import list_elements
from .elements.get_element import get_element
from .elements.add_element import add_element
from .elements.add_tab import add_tab
from .elements.update_element_geometry import update_element_geometry
from .elements.reorder_element import reorder_element
from .elements.move_element_to_container import move_element_to_container
from .elements.save_element_controls import save_element_controls
from .elements.delete_element import delete_element
from .elements.flow_nodes_referencing_element import flow_nodes_referencing_element
from .elements.duplicate_element import duplicate_element
from .elements.rename_element import rename_element
from .elements.element_label import element_label
from .element_types.list_element_types import list_element_types
from .element_types.get_element_type_by_template_screen import get_element_type_by_template_screen
from .element_types.create_element_type import create_element_type
from .element_types.update_element_type import update_element_type
from .element_types.element_type_usage_count import element_type_usage_count
from .element_types.delete_element_type import delete_element_type
from .legacy_actions.list_actions import list_actions
from .legacy_actions.add_action import add_action
from .legacy_actions.get_action import get_action
from .legacy_actions.delete_action import delete_action
from .flow.ensure_flow_schema import ensure_flow_schema
from .flow.list_flow_nodes import list_flow_nodes
from .flow.list_flow_edges import list_flow_edges
from .flow.get_flow_node import get_flow_node
from .flow.add_flow_node import add_flow_node
from .flow.move_flow_node import move_flow_node
from .flow.delete_flow_node import delete_flow_node
from .flow.add_flow_edge import add_flow_edge
from .flow.delete_flow_edge import delete_flow_edge
from .flow.blocks.list_flow_blocks import list_flow_blocks
from .flow.blocks.get_flow_block import get_flow_block
from .flow.blocks.create_flow_block import create_flow_block
from .flow.blocks.update_flow_block import update_flow_block
from .flow.blocks.delete_flow_block import delete_flow_block
from .flow.blocks.blocks_view import blocks_view
from .data_actions.apply_data_action import apply_data_action
from .data_actions.apply_variable_action import apply_variable_action
from .data_actions.apply_add_row_action import apply_add_row_action
from .animations.ensure_animation_schema import ensure_animation_schema
from .animations.list_animation_clips import list_animation_clips
from .animations.get_animation_clip import get_animation_clip
from .animations.add_animation_clip import add_animation_clip
from .animations.update_animation_clip import update_animation_clip
from .animations.delete_animation_clip import delete_animation_clip
from .animations.animate_css_catalog import ANIMATE_CSS_CATALOG, ANIMATE_CSS_LABELS
from .custom_events.list_custom_event_usages import list_custom_event_usages
from .custom_events.delete_custom_event import delete_custom_event
from .payload.full_game_payload import full_game_payload