feat: add in-memory project management
This commit is contained in:
parent
dcf9f09c88
commit
59efdddef9
6 changed files with 285 additions and 40 deletions
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
void lardon3d_layout_draw(
|
||||
const Lardon3DAppState *state,
|
||||
const char *project_name_input,
|
||||
int rows,
|
||||
int cols
|
||||
);
|
||||
|
|
|
|||
15
include/lardon3d/project.h
Normal file
15
include/lardon3d/project.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef LARDON3D_PROJECT_H
|
||||
#define LARDON3D_PROJECT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <lardon3d/app_state.h>
|
||||
|
||||
bool lardon3d_project_set_name(
|
||||
Lardon3DAppState *state,
|
||||
const char *name
|
||||
);
|
||||
|
||||
void lardon3d_project_close(Lardon3DAppState *state);
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@ executable(
|
|||
'src/app_state.c',
|
||||
'src/tui.c',
|
||||
'src/layout.c',
|
||||
'src/project.c',
|
||||
],
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: [ncursesw],
|
||||
|
|
|
|||
42
src/layout.c
42
src/layout.c
|
|
@ -64,6 +64,7 @@ screen_texts(
|
|||
case LARDON3D_SCREEN_PROJECTS:
|
||||
*title = "Projets";
|
||||
*content = "Gestion des projets";
|
||||
*footer = "N Nouveau projet C Fermer le projet ESC Accueil Q Quit";
|
||||
break;
|
||||
case LARDON3D_SCREEN_IMPORT:
|
||||
*title = "Import";
|
||||
|
|
@ -87,7 +88,39 @@ screen_texts(
|
|||
}
|
||||
|
||||
static void
|
||||
draw_content(const Lardon3DAppState *state, int rows, int columns)
|
||||
draw_project_screen(const char *project_name_input, int columns)
|
||||
{
|
||||
draw_text(6, 4, columns - 6, "N : Nouveau projet");
|
||||
draw_text(7, 4, columns - 6, "C : Fermer le projet");
|
||||
draw_text(8, 4, columns - 6, "ESC : Accueil");
|
||||
draw_text(9, 4, columns - 6, "Q : Quitter");
|
||||
|
||||
if (!project_name_input) {
|
||||
return;
|
||||
}
|
||||
|
||||
draw_text(10, 4, columns - 6, "Nom du nouveau projet :");
|
||||
(void)mvaddch(11, 2, '[');
|
||||
(void)mvaddch(11, columns - 3, ']');
|
||||
|
||||
int available = columns - 8;
|
||||
size_t length = strlen(project_name_input);
|
||||
const char *visible = project_name_input;
|
||||
if (length > (size_t)available) {
|
||||
visible += length - (size_t)available;
|
||||
length = (size_t)available;
|
||||
}
|
||||
draw_text(11, 4, available, visible);
|
||||
(void)move(11, 4 + (int)length);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_content(
|
||||
const Lardon3DAppState *state,
|
||||
const char *project_name_input,
|
||||
int rows,
|
||||
int columns
|
||||
)
|
||||
{
|
||||
const char *title;
|
||||
const char *content;
|
||||
|
|
@ -103,12 +136,16 @@ draw_content(const Lardon3DAppState *state, int rows, int columns)
|
|||
draw_text(1, (columns - title_length) / 2, title_length, title);
|
||||
draw_text(3, 2, columns - 4, "Projet");
|
||||
draw_text(4, 4, columns - 6, project);
|
||||
if (state->screen == LARDON3D_SCREEN_PROJECTS) {
|
||||
draw_project_screen(project_name_input, columns);
|
||||
} else {
|
||||
draw_text(
|
||||
(3 + journal_row) / 2,
|
||||
(columns - content_length) / 2,
|
||||
content_length,
|
||||
content
|
||||
);
|
||||
}
|
||||
draw_text(journal_row + 1, 2, columns - 4, "Journal");
|
||||
draw_text(journal_row + 2, 4, columns - 6, state->status_message);
|
||||
draw_text(rows - 2, 2, columns - 4, footer);
|
||||
|
|
@ -117,6 +154,7 @@ draw_content(const Lardon3DAppState *state, int rows, int columns)
|
|||
void
|
||||
lardon3d_layout_draw(
|
||||
const Lardon3DAppState *state,
|
||||
const char *project_name_input,
|
||||
int rows,
|
||||
int columns
|
||||
)
|
||||
|
|
@ -127,7 +165,7 @@ lardon3d_layout_draw(
|
|||
draw_too_small(rows, columns);
|
||||
} else {
|
||||
draw_frame(rows, columns);
|
||||
draw_content(state, rows, columns);
|
||||
draw_content(state, project_name_input, rows, columns);
|
||||
}
|
||||
|
||||
(void)refresh();
|
||||
|
|
|
|||
87
src/project.c
Normal file
87
src/project.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <lardon3d/project.h>
|
||||
|
||||
bool
|
||||
lardon3d_project_set_name(Lardon3DAppState *state, const char *name)
|
||||
{
|
||||
if (!state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
(void)snprintf(
|
||||
state->status_message,
|
||||
sizeof(state->status_message),
|
||||
"Erreur : le nom du projet est vide."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *start = name;
|
||||
while (*start && isspace((unsigned char)*start)) {
|
||||
++start;
|
||||
}
|
||||
|
||||
const char *end = name + strlen(name);
|
||||
while (end > start && isspace((unsigned char)end[-1])) {
|
||||
--end;
|
||||
}
|
||||
|
||||
size_t length = (size_t)(end - start);
|
||||
if (length == 0) {
|
||||
(void)snprintf(
|
||||
state->status_message,
|
||||
sizeof(state->status_message),
|
||||
"Erreur : le nom du projet est vide."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length >= sizeof(state->project_name)) {
|
||||
(void)snprintf(
|
||||
state->status_message,
|
||||
sizeof(state->status_message),
|
||||
"Erreur : le nom du projet est trop long."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
(void)memcpy(state->project_name, start, length);
|
||||
state->project_name[length] = '\0';
|
||||
state->project_loaded = true;
|
||||
(void)snprintf(
|
||||
state->status_message,
|
||||
sizeof(state->status_message),
|
||||
"Projet créé : %s",
|
||||
state->project_name
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
lardon3d_project_close(Lardon3DAppState *state)
|
||||
{
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state->project_loaded) {
|
||||
(void)snprintf(
|
||||
state->status_message,
|
||||
sizeof(state->status_message),
|
||||
"Aucun projet à fermer."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
state->project_loaded = false;
|
||||
state->project_name[0] = '\0';
|
||||
(void)snprintf(
|
||||
state->status_message,
|
||||
sizeof(state->status_message),
|
||||
"Projet fermé."
|
||||
);
|
||||
}
|
||||
167
src/tui.c
167
src/tui.c
|
|
@ -1,16 +1,143 @@
|
|||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <ncurses.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <lardon3d/layout.h>
|
||||
#include <lardon3d/project.h>
|
||||
#include <lardon3d/tui.h>
|
||||
|
||||
enum {
|
||||
PROJECT_INPUT_CAPACITY = 256,
|
||||
MINIMUM_ROWS = 20,
|
||||
MINIMUM_COLUMNS = 72,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
char text[PROJECT_INPUT_CAPACITY];
|
||||
size_t length;
|
||||
} ProjectInput;
|
||||
|
||||
static void
|
||||
redraw(const Lardon3DAppState *state)
|
||||
redraw(const Lardon3DAppState *state, const ProjectInput *input)
|
||||
{
|
||||
int rows;
|
||||
int columns;
|
||||
getmaxyx(stdscr, rows, columns);
|
||||
lardon3d_layout_draw(state, rows, columns);
|
||||
|
||||
const char *text = input->active ? input->text : NULL;
|
||||
lardon3d_layout_draw(state, text, rows, columns);
|
||||
(void)curs_set(
|
||||
input->active && rows >= MINIMUM_ROWS && columns >= MINIMUM_COLUMNS
|
||||
? 1
|
||||
: 0
|
||||
);
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_project_input(
|
||||
Lardon3DAppState *state,
|
||||
ProjectInput *input,
|
||||
int key
|
||||
)
|
||||
{
|
||||
if (key == KEY_RESIZE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == 27) {
|
||||
input->active = false;
|
||||
(void)snprintf(
|
||||
state->status_message,
|
||||
sizeof(state->status_message),
|
||||
"Création du projet annulée."
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == '\n' || key == '\r' || key == KEY_ENTER) {
|
||||
(void)lardon3d_project_set_name(state, input->text);
|
||||
input->active = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == KEY_BACKSPACE || key == 127 || key == '\b') {
|
||||
if (input->length > 0) {
|
||||
--input->length;
|
||||
input->text[input->length] = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key >= 0 && key <= UCHAR_MAX && isprint((unsigned char)key)) {
|
||||
if (input->length + 1 >= sizeof(input->text)) {
|
||||
(void)lardon3d_project_set_name(state, input->text);
|
||||
input->active = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
input->text[input->length] = (char)key;
|
||||
++input->length;
|
||||
input->text[input->length] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_normal_input(
|
||||
Lardon3DAppState *state,
|
||||
ProjectInput *input,
|
||||
int key
|
||||
)
|
||||
{
|
||||
if (key == 'q' || key == 'Q') {
|
||||
state->running = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case KEY_F(1):
|
||||
state->screen = LARDON3D_SCREEN_HELP;
|
||||
return true;
|
||||
case KEY_F(2):
|
||||
state->screen = LARDON3D_SCREEN_PROJECTS;
|
||||
return true;
|
||||
case KEY_F(3):
|
||||
state->screen = LARDON3D_SCREEN_IMPORT;
|
||||
return true;
|
||||
case KEY_F(4):
|
||||
state->screen = LARDON3D_SCREEN_VIEWER;
|
||||
return true;
|
||||
case 27:
|
||||
state->screen = LARDON3D_SCREEN_HOME;
|
||||
return true;
|
||||
case KEY_RESIZE:
|
||||
return true;
|
||||
case 'n':
|
||||
case 'N':
|
||||
if (state->screen == LARDON3D_SCREEN_PROJECTS) {
|
||||
*input = (ProjectInput) {
|
||||
.active = true,
|
||||
.text = "",
|
||||
.length = 0,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case 'c':
|
||||
case 'C':
|
||||
if (state->screen == LARDON3D_SCREEN_PROJECTS) {
|
||||
lardon3d_project_close(state);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -36,45 +163,21 @@ lardon3d_tui_run(Lardon3DAppState *state)
|
|||
return false;
|
||||
}
|
||||
|
||||
redraw(state);
|
||||
ProjectInput input = {0};
|
||||
redraw(state, &input);
|
||||
|
||||
while (state->running) {
|
||||
int key = getch();
|
||||
|
||||
if (key == 'q' || key == 'Q') {
|
||||
state->running = false;
|
||||
continue;
|
||||
}
|
||||
if (key == ERR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool should_redraw = true;
|
||||
switch (key) {
|
||||
case KEY_F(1):
|
||||
state->screen = LARDON3D_SCREEN_HELP;
|
||||
break;
|
||||
case KEY_F(2):
|
||||
state->screen = LARDON3D_SCREEN_PROJECTS;
|
||||
break;
|
||||
case KEY_F(3):
|
||||
state->screen = LARDON3D_SCREEN_IMPORT;
|
||||
break;
|
||||
case KEY_F(4):
|
||||
state->screen = LARDON3D_SCREEN_VIEWER;
|
||||
break;
|
||||
case 27:
|
||||
state->screen = LARDON3D_SCREEN_HOME;
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
break;
|
||||
default:
|
||||
should_redraw = false;
|
||||
break;
|
||||
}
|
||||
bool should_redraw = input.active
|
||||
? handle_project_input(state, &input, key)
|
||||
: handle_normal_input(state, &input, key);
|
||||
|
||||
if (should_redraw) {
|
||||
redraw(state);
|
||||
redraw(state, &input);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue