Ajouter le zoom et le déplacement dans la vue graphique #63

Closed
opened 2026-07-21 17:06:00 +02:00 by fy59 · 0 comments
Owner

Ajouter le zoom et le déplacement dans la vue graphique

Contexte

La vue graphique en lecture seule du graphe d’enquête est désormais intégrée à l’application.

InvestigationGraphView affiche les entités actives sous forme de nœuds et les relations actives sous forme de liaisons orientées. Le rendu actuel est déterministe et fonctionne pour un petit nombre d’entités, mais il devient rapidement limité lorsque le graphe dépasse la taille visible de la fenêtre.

La prochaine étape consiste à permettre à l’utilisateur de naviguer dans le canvas sans modifier les données métier.

Objectif

Ajouter à InvestigationGraphView :

  • le zoom avant et arrière ;
  • le déplacement du canvas par glisser-déposer ;
  • un recentrage automatique sur le graphe ;
  • une remise à zéro de la vue.

La navigation doit rester fluide, déterministe et entièrement indépendante du modèle métier.

Architecture attendue

Responsabilités

  • InvestigationGraphModel reste inchangé.
  • InvestigationGraphView conserve l’état d’affichage :
    • facteur de zoom ;
    • translation horizontale ;
    • translation verticale ;
    • état du déplacement en cours.
  • Les transformations graphiques ne sont jamais persistées dans SQLite.
  • Le graphe reste emprunté par la vue.
  • Le Workspace ne gère pas directement les coordonnées du canvas.

État privé minimal

La structure privée de InvestigationGraphView peut contenir au minimum :

double zoom;
double offset_x;
double offset_y;

double drag_start_x;
double drag_start_y;

double drag_origin_offset_x;
double drag_origin_offset_y;

gboolean dragging;

Les noms exacts peuvent évoluer tant que les responsabilités restent claires.

Interactions attendues

Zoom

  • La molette de la souris modifie le facteur de zoom.
  • Le zoom doit être centré autour de la position du pointeur.
  • Le zoom doit être borné.
  • Valeurs recommandées :
    • minimum : 0.25;
    • maximum : 3.0;
    • valeur initiale : 1.0.
  • Le zoom ne doit jamais devenir nul ou négatif.
  • Le zoom doit provoquer un nouveau rendu immédiatement.

Déplacement

  • Le déplacement s’effectue par glisser-déposer avec le bouton principal.
  • Le déplacement commence uniquement lorsqu’un glisser est réellement détecté.
  • Le déplacement doit rester fluide pendant le mouvement.
  • Le relâchement du bouton termine proprement l’opération.
  • Le déplacement ne doit pas modifier les positions internes des nœuds.
  • Le curseur peut changer pendant le déplacement si cela reste simple et fiable.

Recentrage

Lorsqu’un nouveau graphe est chargé :

  • la vue doit être recentrée ;
  • le zoom doit revenir à une valeur cohérente ;
  • l’ensemble du graphe doit être visible autant que possible ;
  • les transformations de l’enquête précédente ne doivent pas être réutilisées.

Une API publique dédiée doit être ajoutée :

void investigation_graph_view_reset_view(
    InvestigationGraphView *graph_view
);

Une fonction interne de recentrage automatique peut être utilisée pour calculer un zoom adapté à la taille disponible.

Transformation du rendu

Le rendu Cairo doit appliquer les transformations dans cet ordre logique :

  1. translation vers la position de la vue ;
  2. mise à l’échelle ;
  3. dessin des relations ;
  4. dessin des nœuds.

Les calculs de disposition des entités restent exprimés dans les coordonnées logiques du graphe.

Les transformations doivent être encapsulées entre :

cairo_save(cairo_context);

et :

cairo_restore(cairo_context);

afin de ne pas modifier les autres éléments de rendu.

Gestion du redimensionnement

Lors du redimensionnement de la fenêtre :

  • le rendu doit rester valide ;
  • le zoom et le déplacement courants doivent être conservés ;
  • le graphe ne doit pas être automatiquement recentré à chaque changement de taille ;
  • aucun saut visuel important ne doit apparaître.

Le recentrage automatique ne doit avoir lieu que :

  • lors du chargement d’un nouveau graphe ;
  • lors d’un appel explicite à investigation_graph_view_reset_view().

Gestion du graphe vide

Lorsque le graphe est absent ou vide :

  • la vue doit afficher son message actuel ;
  • le zoom et le déplacement ne doivent pas provoquer d’erreur ;
  • la remise à zéro doit rester sûre ;
  • aucun avertissement GTK ou Cairo ne doit être généré.

Gestion de la mémoire

  • Aucun nouvel objet GTK ne doit être créé à chaque mouvement de souris.
  • Les contrôleurs d’événements appartiennent au widget GTK.
  • Les callbacks ne doivent conserver aucun pointeur vers un graphe libéré.
  • investigation_graph_view_clear() doit réinitialiser l’état de navigation.
  • investigation_graph_view_free() doit détacher proprement les callbacks et le graphe emprunté.

API publique attendue

L’API existante est conservée.

Ajouter :

void investigation_graph_view_reset_view(
    InvestigationGraphView *graph_view
);

Aucune API publique ne doit exposer directement les coordonnées internes ou le facteur de zoom pour cette première version.

Hors périmètre

Ce ticket n’inclut pas :

  • sélection d’un nœud ;
  • déplacement individuel d’une entité ;
  • création ou suppression d’une relation ;
  • persistance des positions ;
  • mini-carte ;
  • zoom par boutons dans la barre d’outils ;
  • raccourcis clavier avancés ;
  • algorithme de placement par forces ;
  • export d’image ;
  • animations ;
  • menus contextuels.

Ces fonctions feront l’objet de tickets séparés.

Critères d’acceptation

  • La molette permet de zoomer et dézoomer.
  • Le zoom est centré autour du pointeur.
  • Le facteur de zoom reste dans des limites sûres.
  • Le glisser-déposer déplace le canvas.
  • Le déplacement ne modifie pas les données métier.
  • Le rendu reste fluide pendant le déplacement.
  • Le chargement d’un nouveau graphe réinitialise la vue.
  • investigation_graph_view_reset_view() recentre correctement le graphe.
  • Le redimensionnement conserve la navigation courante.
  • Le graphe vide reste affichable sans erreur.
  • Aucun pointeur vers un ancien graphe n’est conservé.
  • Aucun avertissement GTK ou Cairo n’apparaît pendant l’utilisation.
  • make clean && make réussit avec -Werror -Wpedantic.
  • make test réussit.
  • git diff --check ne signale aucune erreur.

Plan d’implémentation conseillé

  1. Ajouter l’état privé du zoom et du déplacement.
  2. Ajouter investigation_graph_view_reset_view().
  3. Appliquer les transformations Cairo au rendu existant.
  4. Ajouter un GtkEventControllerScroll.
  5. Implémenter le zoom centré sur le pointeur.
  6. Ajouter un GtkGestureDrag.
  7. Implémenter le déplacement du canvas.
  8. Réinitialiser la vue lors de set_graph() et clear().
  9. Tester les graphes vides et volumineux.
  10. Tester le changement d’enquête et la fermeture de l’application.

Validation manuelle

  1. Ouvrir une enquête contenant plusieurs entités.
  2. Zoomer vers l’avant et vers l’arrière.
  3. Vérifier que le point sous le curseur reste stable pendant le zoom.
  4. Déplacer le graphe dans toutes les directions.
  5. Redimensionner la fenêtre.
  6. Réinitialiser la vue.
  7. Ouvrir une autre enquête.
  8. Vérifier que l’ancienne position n’est pas réutilisée.
  9. Tester une enquête sans entité.
  10. Fermer l’application pendant et après une interaction.
# Ajouter le zoom et le déplacement dans la vue graphique ## Contexte La vue graphique en lecture seule du graphe d’enquête est désormais intégrée à l’application. `InvestigationGraphView` affiche les entités actives sous forme de nœuds et les relations actives sous forme de liaisons orientées. Le rendu actuel est déterministe et fonctionne pour un petit nombre d’entités, mais il devient rapidement limité lorsque le graphe dépasse la taille visible de la fenêtre. La prochaine étape consiste à permettre à l’utilisateur de naviguer dans le canvas sans modifier les données métier. ## Objectif Ajouter à `InvestigationGraphView` : - le zoom avant et arrière ; - le déplacement du canvas par glisser-déposer ; - un recentrage automatique sur le graphe ; - une remise à zéro de la vue. La navigation doit rester fluide, déterministe et entièrement indépendante du modèle métier. ## Architecture attendue ### Responsabilités - `InvestigationGraphModel` reste inchangé. - `InvestigationGraphView` conserve l’état d’affichage : - facteur de zoom ; - translation horizontale ; - translation verticale ; - état du déplacement en cours. - Les transformations graphiques ne sont jamais persistées dans SQLite. - Le graphe reste emprunté par la vue. - Le `Workspace` ne gère pas directement les coordonnées du canvas. ### État privé minimal La structure privée de `InvestigationGraphView` peut contenir au minimum : ```c double zoom; double offset_x; double offset_y; double drag_start_x; double drag_start_y; double drag_origin_offset_x; double drag_origin_offset_y; gboolean dragging; ``` Les noms exacts peuvent évoluer tant que les responsabilités restent claires. ## Interactions attendues ### Zoom - La molette de la souris modifie le facteur de zoom. - Le zoom doit être centré autour de la position du pointeur. - Le zoom doit être borné. - Valeurs recommandées : - minimum : `0.25`; - maximum : `3.0`; - valeur initiale : `1.0`. - Le zoom ne doit jamais devenir nul ou négatif. - Le zoom doit provoquer un nouveau rendu immédiatement. ### Déplacement - Le déplacement s’effectue par glisser-déposer avec le bouton principal. - Le déplacement commence uniquement lorsqu’un glisser est réellement détecté. - Le déplacement doit rester fluide pendant le mouvement. - Le relâchement du bouton termine proprement l’opération. - Le déplacement ne doit pas modifier les positions internes des nœuds. - Le curseur peut changer pendant le déplacement si cela reste simple et fiable. ### Recentrage Lorsqu’un nouveau graphe est chargé : - la vue doit être recentrée ; - le zoom doit revenir à une valeur cohérente ; - l’ensemble du graphe doit être visible autant que possible ; - les transformations de l’enquête précédente ne doivent pas être réutilisées. Une API publique dédiée doit être ajoutée : ```c void investigation_graph_view_reset_view( InvestigationGraphView *graph_view ); ``` Une fonction interne de recentrage automatique peut être utilisée pour calculer un zoom adapté à la taille disponible. ## Transformation du rendu Le rendu Cairo doit appliquer les transformations dans cet ordre logique : 1. translation vers la position de la vue ; 2. mise à l’échelle ; 3. dessin des relations ; 4. dessin des nœuds. Les calculs de disposition des entités restent exprimés dans les coordonnées logiques du graphe. Les transformations doivent être encapsulées entre : ```c cairo_save(cairo_context); ``` et : ```c cairo_restore(cairo_context); ``` afin de ne pas modifier les autres éléments de rendu. ## Gestion du redimensionnement Lors du redimensionnement de la fenêtre : - le rendu doit rester valide ; - le zoom et le déplacement courants doivent être conservés ; - le graphe ne doit pas être automatiquement recentré à chaque changement de taille ; - aucun saut visuel important ne doit apparaître. Le recentrage automatique ne doit avoir lieu que : - lors du chargement d’un nouveau graphe ; - lors d’un appel explicite à `investigation_graph_view_reset_view()`. ## Gestion du graphe vide Lorsque le graphe est absent ou vide : - la vue doit afficher son message actuel ; - le zoom et le déplacement ne doivent pas provoquer d’erreur ; - la remise à zéro doit rester sûre ; - aucun avertissement GTK ou Cairo ne doit être généré. ## Gestion de la mémoire - Aucun nouvel objet GTK ne doit être créé à chaque mouvement de souris. - Les contrôleurs d’événements appartiennent au widget GTK. - Les callbacks ne doivent conserver aucun pointeur vers un graphe libéré. - `investigation_graph_view_clear()` doit réinitialiser l’état de navigation. - `investigation_graph_view_free()` doit détacher proprement les callbacks et le graphe emprunté. ## API publique attendue L’API existante est conservée. Ajouter : ```c void investigation_graph_view_reset_view( InvestigationGraphView *graph_view ); ``` Aucune API publique ne doit exposer directement les coordonnées internes ou le facteur de zoom pour cette première version. ## Hors périmètre Ce ticket n’inclut pas : - sélection d’un nœud ; - déplacement individuel d’une entité ; - création ou suppression d’une relation ; - persistance des positions ; - mini-carte ; - zoom par boutons dans la barre d’outils ; - raccourcis clavier avancés ; - algorithme de placement par forces ; - export d’image ; - animations ; - menus contextuels. Ces fonctions feront l’objet de tickets séparés. ## Critères d’acceptation - [x] La molette permet de zoomer et dézoomer. - [x] Le zoom est centré autour du pointeur. - [x] Le facteur de zoom reste dans des limites sûres. - [x] Le glisser-déposer déplace le canvas. - [x] Le déplacement ne modifie pas les données métier. - [x] Le rendu reste fluide pendant le déplacement. - [x] Le chargement d’un nouveau graphe réinitialise la vue. - [x] `investigation_graph_view_reset_view()` recentre correctement le graphe. - [x] Le redimensionnement conserve la navigation courante. - [x] Le graphe vide reste affichable sans erreur. - [x] Aucun pointeur vers un ancien graphe n’est conservé. - [x] Aucun avertissement GTK ou Cairo n’apparaît pendant l’utilisation. - [x] `make clean && make` réussit avec `-Werror -Wpedantic`. - [x] `make test` réussit. - [x] `git diff --check` ne signale aucune erreur. ## Plan d’implémentation conseillé 1. Ajouter l’état privé du zoom et du déplacement. 2. Ajouter `investigation_graph_view_reset_view()`. 3. Appliquer les transformations Cairo au rendu existant. 4. Ajouter un `GtkEventControllerScroll`. 5. Implémenter le zoom centré sur le pointeur. 6. Ajouter un `GtkGestureDrag`. 7. Implémenter le déplacement du canvas. 8. Réinitialiser la vue lors de `set_graph()` et `clear()`. 9. Tester les graphes vides et volumineux. 10. Tester le changement d’enquête et la fermeture de l’application. ## Validation manuelle 1. Ouvrir une enquête contenant plusieurs entités. 2. Zoomer vers l’avant et vers l’arrière. 3. Vérifier que le point sous le curseur reste stable pendant le zoom. 4. Déplacer le graphe dans toutes les directions. 5. Redimensionner la fenêtre. 6. Réinitialiser la vue. 7. Ouvrir une autre enquête. 8. Vérifier que l’ancienne position n’est pas réutilisée. 9. Tester une enquête sans entité. 10. Fermer l’application pendant et après une interaction.
fy59 closed this issue 2026-07-21 17:33:36 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: fy59/labfy-investigation#63
No description provided.