feat(widget): create workspace

This commit is contained in:
grayTerminal-sh 2026-07-12 23:54:47 +02:00
parent d16e0229c4
commit b1f931d8f2
5 changed files with 360 additions and 19 deletions

View file

@ -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
```

View file

@ -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 <gtk/gtk.h>
/**
* @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

View file

@ -5,6 +5,7 @@
#include "views/main_window.h" #include "views/main_window.h"
#include "widgets/sidebar.h" #include "widgets/sidebar.h"
#include "widgets/workspace.h"
#include <glib.h> #include <glib.h>
@ -35,7 +36,7 @@ struct MainWindow
GtkWindow *window; GtkWindow *window;
GtkWidget *main_box; GtkWidget *main_box;
GtkWidget *main_paned; GtkWidget *main_paned;
GtkWidget *workspace; Workspace *workspace;
GtkWidget *status_label; GtkWidget *status_label;
Sidebar *sidebar; Sidebar *sidebar;
}; };
@ -44,6 +45,7 @@ MainWindow *main_window_new(GtkApplication *application)
{ {
MainWindow *main_window = NULL; MainWindow *main_window = NULL;
GtkWidget *sidebar_widget = NULL; GtkWidget *sidebar_widget = NULL;
GtkWidget *workspace_widget = NULL;
if (application == NULL) if (application == NULL)
{ {
@ -125,24 +127,23 @@ MainWindow *main_window_new(GtkApplication *application)
return NULL; return NULL;
} }
/* main_window->workspace = workspace_new();
* La zone de travail est encore vide.
* Elle accueillera plus tard les pages de l'application. if (main_window->workspace == NULL)
*/ {
main_window->workspace = gtk_box_new( main_window_free(main_window);
GTK_ORIENTATION_VERTICAL, return NULL;
0 }
workspace_widget = workspace_get_widget(
main_window->workspace
); );
gtk_widget_set_hexpand( if (workspace_widget == NULL)
main_window->workspace, {
TRUE main_window_free(main_window);
); return NULL;
}
gtk_widget_set_vexpand(
main_window->workspace,
TRUE
);
/* /*
* Placement des deux composants dans GtkPaned. * Placement des deux composants dans GtkPaned.
@ -154,7 +155,7 @@ MainWindow *main_window_new(GtkApplication *application)
gtk_paned_set_end_child( gtk_paned_set_end_child(
GTK_PANED(main_window->main_paned), 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. * Les widgets GTK, eux, restent gérés par GTK.
*/ */
workspace_free(main_window->workspace);
sidebar_free(main_window->sidebar); sidebar_free(main_window->sidebar);
g_free(main_window); g_free(main_window);

View file

@ -0,0 +1,137 @@
/******************************************************************************
* @file workspace.c
* @brief Implémentation de la zone principale de travail.
******************************************************************************/
#include "widgets/workspace.h"
#include <glib.h>
/**
* @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);
}