From b1f931d8f274c017fc7ff982a614f9ba772b5e30 Mon Sep 17 00:00:00 2001 From: grayTerminal-sh Date: Sun, 12 Jul 2026 23:54:47 +0200 Subject: [PATCH] feat(widget): create workspace --- docs/tickets/closed/TICKET-006.md | 153 ++++++++++++++++++ .../include/widgets/workspace.h | 49 ++++++ labfy-investigation/labfy-investigation | Bin 46728 -> 49320 bytes labfy-investigation/src/views/main_window.c | 40 ++--- labfy-investigation/src/widgets/workspace.c | 137 ++++++++++++++++ 5 files changed, 360 insertions(+), 19 deletions(-) create mode 100644 docs/tickets/closed/TICKET-006.md create mode 100644 labfy-investigation/include/widgets/workspace.h create mode 100644 labfy-investigation/src/widgets/workspace.c diff --git a/docs/tickets/closed/TICKET-006.md b/docs/tickets/closed/TICKET-006.md new file mode 100644 index 0000000..04d1736 --- /dev/null +++ b/docs/tickets/closed/TICKET-006.md @@ -0,0 +1,153 @@ +# Ticket #006 + +## Titre + +Créer le module `Workspace`. + +--- + +## Objectif + +Créer un composant graphique représentant la zone principale de travail de Labfy Investigation. + +Le module doit être indépendant du reste de l'interface afin de pouvoir évoluer sans modifier `MainWindow`. + +--- + +## Responsabilités + +Le module `Workspace` doit : + +- créer la zone centrale de l'application ; +- afficher une page d'accueil lorsqu'aucune enquête n'est ouverte ; +- fournir un widget racine réutilisable ; +- gérer uniquement son interface graphique. + +--- + +## Hors périmètre + +Ce ticket ne doit pas : + +- afficher les preuves ; +- afficher les entités ; +- afficher un PDF ; +- afficher une image ; +- communiquer avec SQLite ; +- charger une enquête. + +--- + +## Architecture + +```text +MainWindow +├── Sidebar +├── Workspace +└── StatusBar +``` + +Le module appartient à la couche **Widgets**. + +Aucune logique métier. + +--- + +## Fichiers concernés + +```text +include/widgets/workspace.h +src/widgets/workspace.c +``` + +--- + +## Interface publique + +```c +Workspace *workspace_new(void); + +GtkWidget *workspace_get_widget( + const Workspace *workspace +); + +void workspace_free( + Workspace *workspace +); +``` + +--- + +## Interface graphique attendue + +```text ++-------------------------------------------------------------+ +| | +| | +| Labfy Investigation | +| | +| Aucune enquête ouverte | +| | +| Sélectionnez ou créez une enquête | +| | +| | ++-------------------------------------------------------------+ +``` + +--- + +## Évolutions prévues + +Cette zone accueillera plus tard : + +- visualiseur d'image ; +- lecteur PDF ; +- chronologie ; +- fiche personne ; +- fiche IBAN ; +- fiche email ; +- fiche téléphone ; +- rapports ; +- cartes ; +- résultats OSINT. + +Le module doit donc rester générique. + +--- + +## Contraintes + +- GTK4 uniquement ; +- structure opaque ; +- aucune variable globale ; +- documentation Doxygen ; +- C17 ; +- compilation sans warning. + +--- + +## Critères d'acceptation + +- [ ] Le projet compile. +- [ ] Le Workspace apparaît dans MainWindow. +- [ ] Le texte d'accueil est centré. +- [ ] Sidebar et Workspace sont totalement indépendants. +- [ ] Aucun warning. +- [ ] Aucun Gtk-CRITICAL. + +--- + +## Tests + +- lancement ; +- redimensionnement de la fenêtre ; +- fermeture ; +- vérification visuelle. + +--- + +## Commit attendu + +```text +feat(widget): create workspace +``` diff --git a/labfy-investigation/include/widgets/workspace.h b/labfy-investigation/include/widgets/workspace.h new file mode 100644 index 0000000..391f59e --- /dev/null +++ b/labfy-investigation/include/widgets/workspace.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * @file workspace.h + * @brief Interface publique de la zone principale de travail. + ******************************************************************************/ + +#ifndef LABFY_INVESTIGATION_WORKSPACE_H +#define LABFY_INVESTIGATION_WORKSPACE_H + +#include + +/** + * @brief Représentation opaque de la zone de travail. + * + * La structure réelle est définie dans workspace.c. + * Les autres modules manipulent uniquement un pointeur vers Workspace. + */ +typedef struct Workspace Workspace; + +/** + * @brief Crée une nouvelle zone de travail. + * + * @return Une nouvelle zone de travail, ou NULL en cas d'échec. + */ +Workspace *workspace_new(void); + +/** + * @brief Retourne le widget GTK racine de la zone de travail. + * + * Le widget retourné appartient au module Workspace et ne doit pas être + * détruit directement par le code appelant. + * + * @param workspace Zone de travail à consulter. + * + * @return Le widget racine, ou NULL si workspace est NULL. + */ +GtkWidget *workspace_get_widget( + const Workspace *workspace +); + +/** + * @brief Libère la structure d'encapsulation de la zone de travail. + * + * Cette fonction accepte NULL. + * + * @param workspace Zone de travail à libérer. + */ +void workspace_free(Workspace *workspace); + +#endif diff --git a/labfy-investigation/labfy-investigation b/labfy-investigation/labfy-investigation index 6b47849d4537181c5aca9be1c7f8489d77a5f4a0..962e4431c0bc78fe91d99f97a03a3af7bcb39b45 100755 GIT binary patch delta 10388 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 delta 8129 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 diff --git a/labfy-investigation/src/views/main_window.c b/labfy-investigation/src/views/main_window.c index bb68b47..ee5d0f9 100644 --- a/labfy-investigation/src/views/main_window.c +++ b/labfy-investigation/src/views/main_window.c @@ -5,6 +5,7 @@ #include "views/main_window.h" #include "widgets/sidebar.h" +#include "widgets/workspace.h" #include @@ -35,7 +36,7 @@ struct MainWindow GtkWindow *window; GtkWidget *main_box; GtkWidget *main_paned; - GtkWidget *workspace; + Workspace *workspace; GtkWidget *status_label; Sidebar *sidebar; }; @@ -44,6 +45,7 @@ MainWindow *main_window_new(GtkApplication *application) { MainWindow *main_window = NULL; GtkWidget *sidebar_widget = NULL; + GtkWidget *workspace_widget = NULL; if (application == NULL) { @@ -125,25 +127,24 @@ MainWindow *main_window_new(GtkApplication *application) return NULL; } - /* - * La zone de travail est encore vide. - * Elle accueillera plus tard les pages de l'application. - */ - main_window->workspace = gtk_box_new( - GTK_ORIENTATION_VERTICAL, - 0 - ); - - gtk_widget_set_hexpand( - main_window->workspace, - TRUE - ); - - gtk_widget_set_vexpand( - main_window->workspace, - TRUE + main_window->workspace = workspace_new(); + + if (main_window->workspace == NULL) + { + main_window_free(main_window); + return NULL; + } + + workspace_widget = workspace_get_widget( + main_window->workspace ); + if (workspace_widget == NULL) + { + main_window_free(main_window); + return NULL; + } + /* * Placement des deux composants dans GtkPaned. */ @@ -154,7 +155,7 @@ MainWindow *main_window_new(GtkApplication *application) gtk_paned_set_end_child( GTK_PANED(main_window->main_paned), - main_window->workspace + workspace_widget ); /* @@ -280,6 +281,7 @@ void main_window_free(MainWindow *main_window) * * Les widgets GTK, eux, restent gérés par GTK. */ + workspace_free(main_window->workspace); sidebar_free(main_window->sidebar); g_free(main_window); diff --git a/labfy-investigation/src/widgets/workspace.c b/labfy-investigation/src/widgets/workspace.c new file mode 100644 index 0000000..a8a6e67 --- /dev/null +++ b/labfy-investigation/src/widgets/workspace.c @@ -0,0 +1,137 @@ +/****************************************************************************** + * @file workspace.c + * @brief Implémentation de la zone principale de travail. + ******************************************************************************/ + +#include "widgets/workspace.h" + +#include + +/** + * @struct Workspace + * @brief Représentation interne de la zone de travail. + * + * Cette structure reste privée au module. Les autres fichiers utilisent + * uniquement le type opaque déclaré dans workspace.h. + */ +struct Workspace +{ + GtkWidget *root_widget; + GtkWidget *welcome_box; + GtkWidget *title_label; + GtkWidget *status_label; + GtkWidget *instruction_label; +}; + +Workspace *workspace_new(void) +{ + Workspace *workspace = NULL; + + workspace = g_new0(Workspace, 1); + + workspace->root_widget = gtk_box_new( + GTK_ORIENTATION_VERTICAL, + 0 + ); + + if (workspace->root_widget == NULL) + { + workspace_free(workspace); + return NULL; + } + + gtk_widget_set_hexpand( + workspace->root_widget, + TRUE + ); + + gtk_widget_set_vexpand( + workspace->root_widget, + TRUE + ); + + workspace->welcome_box = gtk_box_new( + GTK_ORIENTATION_VERTICAL, + 12 + ); + + if (workspace->welcome_box == NULL) + { + workspace_free(workspace); + return NULL; + } + + /* + * Le conteneur d'accueil est centré horizontalement et verticalement + * dans l'espace disponible. + */ + gtk_widget_set_halign( + workspace->welcome_box, + GTK_ALIGN_CENTER + ); + + gtk_widget_set_valign( + workspace->welcome_box, + GTK_ALIGN_CENTER + ); + + workspace->title_label = gtk_label_new( + "Labfy Investigation" + ); + + workspace->status_label = gtk_label_new( + "Aucune enquête ouverte" + ); + + workspace->instruction_label = gtk_label_new( + "Sélectionnez ou créez une enquête" + ); + + gtk_box_append( + GTK_BOX(workspace->welcome_box), + workspace->title_label + ); + + gtk_box_append( + GTK_BOX(workspace->welcome_box), + workspace->status_label + ); + + gtk_box_append( + GTK_BOX(workspace->welcome_box), + workspace->instruction_label + ); + + gtk_box_append( + GTK_BOX(workspace->root_widget), + workspace->welcome_box + ); + + return workspace; +} + +GtkWidget *workspace_get_widget( + const Workspace *workspace +) +{ + if (workspace == NULL) + { + return NULL; + } + + return workspace->root_widget; +} + +void workspace_free(Workspace *workspace) +{ + if (workspace == NULL) + { + return; + } + + /* + * Les widgets GTK sont intégrés dans l'arbre de widgets de MainWindow. + * GTK gère donc leur destruction. + */ + g_free(workspace); +}