gol

Implementation of Conway's Game of Life writen in C
git clone git://git.dimitrijedobrota.com/gol.git
Log | Files | Refs | README

commit 875e9d53a57e3a6e89fa6e6239220986e25281d3
parent 1fbb80b7635b1b38d38cb42a37b4007f61ef6629
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Mon, 30 May 2022 19:15:47 +0200

Visual selection of the cells and status bar

- In visual mode you can select the pattern to be saved
- Save/Load menu for patter as well as the whole game
- Ability to save in a new file with name selection
- Optional NO_UNICODE mode, use make NO_UNICODE
- Status bar that displays basic game information
- Status bar does not appear until the game is started
- Ability to change time between screen updates in game
- General performance and cleanup improvement

Diffstat:
MMakefile | 5+++--
Minclude/display.h | 17+++++++++++------
Minclude/file.h | 5++++-
Minclude/utils.h | 2--
Minclude/window.h | 9+++++++--
Msrc/display.c | 190++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/file.c | 14++++++++++++--
Msrc/main.c | 275+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/window.c | 55++++++++++++++++++++++++++++++++++++++++---------------
9 files changed, 414 insertions(+), 158 deletions(-)

diff --git a/Makefile b/Makefile @@ -17,7 +17,8 @@ OBJS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS)) all: $(BIN) debug: CFLAGS +=-ggdb -Wall -debug: ${BIN} +NO_UNICODE: CFLAGS += -D NO_UNICODE +NO_UNICODE debug: ${BIN} $(BIN): $(OBJS) $(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@ @@ -33,4 +34,4 @@ clean: rm -f $(BIN) $(OBJS) endif -.PHONY: all clean debug +.PHONY: all clean debug NO_UNICODE diff --git a/include/display.h b/include/display.h @@ -1,15 +1,15 @@ #ifndef DISPLAY_H #define DISPLAY_H -#include "window.h" #include "logic.h" +#include "window.h" extern window_T MAIN_w; typedef int (*input_f)(int); struct menu_T { - void (*callback)(window_T, char *, int); + void (*callback)(char *, int); char *name; }; @@ -20,16 +20,21 @@ struct imenu_T { char *buffer; }; +extern int screen_offset_x, screen_offset_y; +extern int cursor_offset_x, cursor_offset_y; + int input(WINDOW *win, char *buffer, int size, input_f crit); int display_start(void); int display_stop(void); -void display_menu(window_T win, struct menu_T *items, int size); +void display_menu(window_T wind, char *name, struct menu_T *items, int size); int display_imenu(window_T wind, struct imenu_T *items, int size); -void display_game(window_T wind, cell **mat, int w, int h, int screen_offset_y, - int screen_offset_x, int *cursor_offset_y, - int *cursor_offset_x); +void display_game(window_T wind, cell **mat, int h, int w, int ph, int pw); +void display_select(window_T wind, cell **mat, int w, int h); +void display_status(window_T wind, unsigned long int generation, int gen_step, + int height, int wight, int play, int dt, int cursor_y, + int cursor_x); void handle_winch(int sig); diff --git a/include/file.h b/include/file.h @@ -8,6 +8,9 @@ void load_files(void); void free_files(void); int file_select(char *ext, char ***buffer); -void load_file(window_T win, char *pass, int index); +void file_load_pattern(char *name, int index); +void file_save_pattern(char *name, int index); +void file_load(char *name, int index); +void file_save(char *name, int index); #endif diff --git a/include/utils.h b/include/utils.h @@ -15,13 +15,11 @@ { \ resize_term(0, 0); \ handle_winch(10); \ - goto redraw; \ } #else #define HANDLE_RESIZE \ { \ handle_winch(10); \ - goto redraw; \ } #endif #endif diff --git a/include/window.h b/include/window.h @@ -9,10 +9,13 @@ typedef struct T *T; T window_new(void); void window_free(T self); T window_init(T self); -T window_split(T self, int hor, int a, int b); -T window_center(T self, int tmp, int h, int w); +T window_split(T self, int hor, int a, int b, char *name1, char *name2); +void window_unsplit(T self); +T window_center(T self, int tmp, int h, int w, char *name); void window_update_children(T self); +WINDOW *WINDOW_new(T self); + T window_sibiling(T self); int window_height(T self); int window_wight(T self); @@ -20,6 +23,8 @@ WINDOW *window_win(T self); void window_settings(WINDOW *win); void window_clear(T self); +void window_set_title(T self, char *title); + void wcenter_horizontal(T window, int y, int n); int wcenter_vertical(T window, int n); void cursor_offset(WINDOW *win, int oy, int ox); diff --git a/src/display.c b/src/display.c @@ -11,10 +11,11 @@ #define center_vertical(n) wcenter_vertical(MAIN_W, n); #define center_horizontal(y, n) wcenter_horizontal(MAIN_W, y, n); -#define CHAR_CIRCLE L'\u26AB' -#define CHAR_SQUARE L'\u2B1B' -#define CHAR_SQUARED L'\u2B1C' -#define CHAR_CIRCLE_DOT L'\u2299' +#define CHAR_BLANK " " +#define CHAR_CIRCLE "\u26AB" +#define CHAR_SQUARE "\u2B1B" +#define CHAR_SQUARED "\u2B1C" +#define CHAR_CIRCLE_DOT "\u2299" window_T MAIN_w = NULL; @@ -77,7 +78,7 @@ int display_imenu(window_T wind, struct imenu_T *items, int size) { window_clear(wind); redraw:; win = window_win(wind); - y_offset = wcenter_vertical(wind, size); + y_offset = wcenter_vertical(wind, size * 2 - 1); for (int i = 0; i < size; i++) { wcenter_horizontal(wind, y_offset + 2 * i, 20); @@ -119,7 +120,7 @@ redraw:; curs_set(0); } -void display_menu(window_T wind, struct menu_T *items, int size) { +void display_menu(window_T wind, char *name, struct menu_T *items, int size) { WINDOW *win; int current = 0; @@ -128,10 +129,12 @@ void display_menu(window_T wind, struct menu_T *items, int size) { if ((len = strlen(items[i].name)) > maxi) maxi = len; + window_set_title(wind, name); + window_clear(wind); redraw:; win = window_win(wind); int CLINES = LINES, CCOLS = COLS; - int y_offset = wcenter_vertical(wind, size * 2); + int y_offset = wcenter_vertical(wind, size * 2 - 1); while (TRUE) { CLAMP(current, 0, size - 1); @@ -144,17 +147,15 @@ redraw:; while (TRUE) { int c = getch(); - if (c == 'k' || c == KEY_UP) { + if (c == 'k' || c == 'w' || c == KEY_UP) { current--; break; - } else if (c == 'j' || c == KEY_DOWN) { + } else if (c == 'j' || c == 's' || c == KEY_DOWN) { current++; break; } else if (c == '\n') { wattrset(win, COLOR_PAIR(0)); - window_clear(wind); - items[current].callback(wind, items[current].name, current); - /* window_clear(wind); */ + items[current].callback(items[current].name, current); return; } else if (c == 27) return; @@ -166,51 +167,134 @@ redraw:; } } -#define y_at(y) (y + screen_offset_y + h) % h + 1 -#define x_at(x) (x + screen_offset_x + w) % w + 1 +#define y_at(y) (y + screen_offset_y + h) % h + 1 +#define x_at(x) (x + screen_offset_x + w) % w + 1 +#define at(y, x) mat[y_at(y)][x_at(x)] +#define at_offset(off) mat[y_at(off##_y)][x_at(off##_x)] + +#ifndef NO_UNICODE +#define print_cell(win, k, l, blank) \ + if (at(k, l)) \ + waddstr(win, CHAR_CIRCLE); \ + else \ + waddstr(win, blank); +#else +#define print_cell(win, i, j, blank) waddstr(win, blank); +#endif -void display_game(window_T wind, cell **mat, int w, int h, int screen_offset_y, - int screen_offset_x, int *cursor_offset_y, - int *cursor_offset_x) { - WINDOW *win = window_win(wind); - wattrset(win, COLOR_PAIR(0)); +#define print_cells(win, start_i, end_i, start_j, end_j, color_offset, blank) \ + for (int i = start_i; i < end_i; i++) { \ + wmove(win, i + 1, 1 + start_j * 2); \ + for (int j = start_j; j < end_j; j++) { \ + wattrset(win, COLOR_PAIR((mat[y_at(i)][x_at(j)]) + color_offset)); \ + print_cell(win, i, j, blank); \ + } \ + } - int ph = window_height(wind), pw = window_wight(wind) / 2; +int screen_offset_x, screen_offset_y; +int cursor_offset_x, cursor_offset_y; +void display_game(window_T wind, cell **mat, int h, int w, int ph, int pw) { + WINDOW *win = window_win(wind); #ifdef _WIN32 window_clear(wind); #endif - for (int i = 0; i < ph; i++) { - wmove(win, i + 1, 1); - for (int j = 0; j < pw; j++) { - wattrset(win, COLOR_PAIR((mat[y_at(i)][x_at(j)]) + 2)); - - if (mat[y_at(i)][x_at(j)]) - waddstr(win, "\u26AB"); - else - waddstr(win, " "); + print_cells(win, 0, ph, 0, pw, 2, CHAR_BLANK); + + wmove(win, cursor_offset_y + 1, cursor_offset_x * 2 + 1); + wattrset(win, COLOR_PAIR(at_offset(cursor_offset) + 5)); + + print_cell(win, cursor_offset_y, cursor_offset_x, "<>"); + + wrefresh(win); +} + +void display_select(window_T wind, cell **mat, int w, int h) { + int current_offset_y = cursor_offset_y; + int current_offset_x = cursor_offset_x; + +redraw:; + int CLINES = LINES, CCOLS = COLS; + WINDOW *new = WINDOW_new(wind); + WINDOW *win = window_win(wind); + + overlay(win, new); + wrefresh(new); + + int ph = window_height(wind), pw = window_wight(wind) / 2; + nodelay(stdscr, 0); + while (TRUE) { + int start_i = MIN(cursor_offset_y, current_offset_y); + int end_i = MAX(cursor_offset_y, current_offset_y); + int start_j = MIN(cursor_offset_x, current_offset_x); + int end_j = MAX(cursor_offset_x, current_offset_x); + + print_cells(new, start_i, end_i + 1, start_j, end_j + 1, 8, CHAR_BLANK); + wrefresh(new); + + if (is_term_resized(CLINES, CCOLS)) { + flushinp(); + delwin(new); + HANDLE_RESIZE; + ph = window_height(wind), pw = window_wight(wind) / 2; + display_game(wind, mat, w, h, ph, pw); + goto redraw; } - } - CLAMP(*cursor_offset_y, 0, ph - 1); - CLAMP(*cursor_offset_x, 0, pw - 1); + int c = getch(); + switch (c) { + // offset selection + case 'w': + case 'W': + current_offset_y--; + break; + case 's': + case 'S': + current_offset_y++; + break; + case 'a': + case 'A': + current_offset_x--; + break; + case 'd': + case 'D': + current_offset_x++; + break; + case '\n': + save_pattern(); - wmove(win, *cursor_offset_y + 1, *cursor_offset_x * 2 + 1); - wattrset(win, COLOR_PAIR( - (mat[y_at(*cursor_offset_y)][x_at(*cursor_offset_x)]) + 5)); + // quit + case 27: + case 'q': + case 'Q': + nodelay(stdscr, 1); + delwin(new); + return; + defalut: + continue; + } - if (mat[y_at(*cursor_offset_y)][x_at(*cursor_offset_x)]) - waddstr(win, "\u26AB"); - else - waddstr(win, " "); + CLAMP(current_offset_y, 0, ph - 1); + CLAMP(current_offset_x, 0, pw - 1); - wrefresh(win); + wclear(new); + overlay(win, new); + } } -#define LMAX 8 -#define LEFT 0 -#define CENTER 1 -#define RIGHT 2 +void display_status(window_T wind, unsigned long int gen, int gen_step, + int height, int wight, int play, int dt, int cursor_y, + int cursor_x) { + WINDOW *win = window_win(wind); + + wmove(win, 1, 1); + wprintw(win, " | %5s | ", play ? "play" : "pause"); + wprintw(win, "Size: %dx%d | ", height, wight); + wprintw(win, "Generation: %10lu(+%d) | ", gen, gen_step); + wprintw(win, "dt: %4dms | ", dt); + wprintw(win, "Cursor: %4dx%-4d | ", cursor_y, cursor_x); + wrefresh(win); +} void curses_start(void) { initscr(); @@ -226,6 +310,7 @@ void curses_start(void) { init_pair(0, COLOR_WHITE, -1); init_pair(1, COLOR_RED, -1); +#ifndef NO_UNICODE init_pair(2, COLOR_WHITE, -1); init_pair(3, COLOR_WHITE, -1); init_pair(4, COLOR_RED, -1); @@ -233,6 +318,23 @@ void curses_start(void) { init_pair(5, COLOR_WHITE, COLOR_CYAN); init_pair(6, COLOR_WHITE, COLOR_CYAN); init_pair(7, COLOR_RED, COLOR_CYAN); + + init_pair(8, COLOR_WHITE, COLOR_YELLOW); + init_pair(9, COLOR_WHITE, COLOR_YELLOW); + init_pair(10, COLOR_RED, COLOR_YELLOW); +#else + init_pair(2, COLOR_WHITE, -1); + init_pair(3, COLOR_WHITE, COLOR_WHITE); + init_pair(4, COLOR_RED, COLOR_RED); + + init_pair(5, COLOR_YELLOW, -1); + init_pair(6, COLOR_YELLOW, COLOR_WHITE); + init_pair(7, COLOR_YELLOW, COLOR_RED); + + init_pair(8, COLOR_WHITE, COLOR_YELLOW); + init_pair(9, COLOR_WHITE, COLOR_WHITE); + init_pair(10, COLOR_RED, COLOR_RED); +#endif } void curses_stop(void) { diff --git a/src/file.c b/src/file.c @@ -130,6 +130,16 @@ int file_select(char *ext, char ***buffer) { return size; } -void load_files(void) { loaded_files = file_fromDirectory(); } +void load_files(void) { + if (loaded_files) + file_free(loaded_files); + loaded_files = file_fromDirectory(); +} + void free_files(void) { file_free(loaded_files); } -void load_file(window_T win, char *pass, int index) { (void)3; } + +// Comming soon... +void file_load_pattern(char *name, int index) { return; } +void file_save_pattern(char *name, int index) { return; } +void file_load(char *name, int index) { return; } +void file_save(char *name, int index) { return; } diff --git a/src/main.c b/src/main.c @@ -15,9 +15,9 @@ #include "window.h" #ifdef _WIN32 -#define TIME_CONST 100 +#define TIME_MOD 1 #else -#define TIME_CONST 100000 +#define TIME_MOD 1000 #endif extern window_T MAIN_w; @@ -26,49 +26,136 @@ extern char *evolution_names[]; extern int evolution_cells[]; extern int evolution_size; -window_T status_w, screen_w, game_w; +window_T menu_w; int top_space = 5; -void game(window_T wind, int w, int h, int ncells) { - int screen_offset_y = 0, screen_offset_x = 0; - int cursor_offset_y = 0, cursor_offset_x = 0; - int in = 3; - int gen_step = 1; - int play = 0; - int gen = 1; +void load_pattern(void); +void save_pattern(void); - window_clear(wind); - game_w = window_center(wind, 0, h, w * 2); +#define y_at(y) (y + screen_offset_y + h) % h + 1 +#define x_at(x) (x + screen_offset_x + w) % w + 1 + +extern int screen_offset_x, screen_offset_y; +extern int cursor_offset_x, cursor_offset_y; + +void game(int h, int w, char *name, int ncells) { + unsigned long int gen = 0; + int gen_step = 1, play = 0, time_const = 100, time_step = 1; + + window_T status_w, screen_w, game_w; + + window_set_title(menu_w, NULL); + window_clear(menu_w); + + status_w = window_split(menu_w, 1, 3, 0, "Status", name); + screen_w = window_sibiling(status_w); + game_w = window_center(screen_w, 0, h, w * 2, "Game"); clock_t start_t, end_t = 0, total_t; + redraw:; int CLINES = LINES, CCOLS = COLS; + int ph = window_height(game_w), pw = window_wight(game_w) / 2; + window_clear(game_w); while (TRUE) { start_t = clock(); - display_game(game_w, mat, w, h, screen_offset_y, screen_offset_x, - &cursor_offset_y, &cursor_offset_x); + + display_status(status_w, gen, gen_step, h, w, play, time_const, + y_at(cursor_offset_y), x_at(cursor_offset_x)); + display_game(game_w, mat, h, w, ph, pw); + if (play) { do_evolution(gen_step); - gen++; + gen += gen_step; } - while ((total_t = (long int)(end_t - start_t)) < TIME_CONST) { + while ((total_t = (long int)(end_t - start_t)) < time_const * TIME_MOD) { refresh(); int c = getch(); switch (c) { + + // toggle pause case 'p': case 'P': play = !play; break; + + // lead pattern + case 'l': + case 'L': + load_pattern(); + window_set_title(screen_w, name); + goto redraw; + break; + + // quit case 27: + case 'q': + case 'Q': + window_unsplit(menu_w); return; + + // change num of evolutions before display case '+': gen_step++; break; case '-': gen_step--; break; + + // change refreshrate + case ']': + time_const += time_step; + break; + case '[': + time_const -= time_step; + break; + } + + if (!play) { + // move cursor around + switch (c) { + case 'w': + case 'W': + cursor_offset_y--; + break; + case 's': + case 'S': + cursor_offset_y++; + break; + case 'a': + case 'A': + cursor_offset_x--; + break; + case 'd': + case 'D': + cursor_offset_x++; + break; + + // toggle cell + case ' ': + mat[y_at(cursor_offset_y)][x_at(cursor_offset_x)] += 1; + mat[y_at(cursor_offset_y)][x_at(cursor_offset_x)] %= ncells; + break; + + // visual selection + case 'v': + case 'V': + display_select(game_w, mat, h, h); + + // clear up the screen afterwards + window_set_title(menu_w, NULL); + window_clear(menu_w); + window_clear(screen_w); + window_clear(status_w); + window_clear(game_w); + break; + } + } + + // move screen around + switch (c) { case KEY_A1: case KEY_C1: case KEY_END: @@ -101,73 +188,47 @@ redraw:; screen_offset_y++; } - if (!play) { - switch (c) { - case 'w': - case 'W': - cursor_offset_y--; - break; - case 's': - case 'S': - cursor_offset_y++; - break; - case 'a': - case 'A': - cursor_offset_x--; - break; - case 'd': - case 'D': - cursor_offset_x++; - break; - case ' ': - mat[(cursor_offset_y + screen_offset_y + h) % h + 1] - [(cursor_offset_x + screen_offset_x + w) % w + 1] = - (mat[(cursor_offset_y + screen_offset_y + h) % h + 1] - [(cursor_offset_x + screen_offset_x + w) % w + 1] + - 1) % - ncells; - break; - } - } screen_offset_x = (screen_offset_x + w) % w; screen_offset_y = (screen_offset_y + h) % h; + + CLAMP(cursor_offset_y, 0, ph - 1); + CLAMP(cursor_offset_x, 0, pw - 1); + CLAMP(gen_step, 1, 10); + CLAMP(time_const, 1, 1000); - /* usleep(100000); */ if (is_term_resized(CLINES, CCOLS)) { flushinp(); HANDLE_RESIZE; goto redraw; } - end_t = clock(); // clock stopped + end_t = clock(); } flushinp(); } } -struct imenu_T imenu_items[] = { - {"Unesi broj redova", 4, isdigit, NULL}, - {"Unesi broj kolona", 4, isdigit, NULL}, -}; -int imenu_items_s = sizeof(imenu_items) / sizeof(struct imenu_T); +void settings(char *pass, int index) { + struct imenu_T imenu_items[] = { + { "Number of rows", 4, isdigit, NULL}, + {"Number of columns", 4, isdigit, NULL}, + }; + int imenu_items_s = sizeof(imenu_items) / sizeof(struct imenu_T); -void settings(window_T wind, char *pass, int index) { - while (TRUE) { - if (display_imenu(wind, imenu_items, imenu_items_s)) { - int row = atoi(imenu_items[0].buffer); - int column = atoi(imenu_items[1].buffer); + window_set_title(menu_w, "Game settings"); + while (display_imenu(menu_w, imenu_items, imenu_items_s)) { + int row = atoi(imenu_items[0].buffer); + int column = atoi(imenu_items[1].buffer); - if (!row || !column) - continue; + if (!row || !column) + continue; - logic_init(column, row); - evolution_init(index); + logic_init(column, row); + evolution_init(index); - game(wind, row, column, evolution_cells[index]); - break; - } else { - break; - } + game(row, column, pass, evolution_cells[index]); + logic_free(); + break; } for (int i = 0; i < imenu_items_s; i++) { @@ -176,39 +237,83 @@ void settings(window_T wind, char *pass, int index) { } } -void mode_select(window_T wind, char *pass, int index) { +void mode_select(char *pass, int index) { struct menu_T *mode_items = malloc(evolution_size * sizeof(struct menu_T)); for (int i = 0; i < evolution_size; i++) { mode_items[i].name = evolution_names[i]; mode_items[i].callback = settings; } - display_menu(wind, mode_items, evolution_size); + display_menu(menu_w, "Game Mode", mode_items, evolution_size); free(mode_items); } -void load(window_T wind, char *pass, int index) { +void new_file(char *pass, int index) { + struct imenu_T new_file_items[] = { + {"Pick a name", 10, isalnum, NULL}, + }; + int new_file_items_s = sizeof(new_file_items) / sizeof(struct imenu_T); + + window_set_title(menu_w, "New File"); + while (display_imenu(menu_w, new_file_items, new_file_items_s)) { + file_save_pattern(new_file_items[0].buffer, index); + break; + } + + for (int i = 0; i < new_file_items_s; i++) { + free(new_file_items[i].buffer); + new_file_items[i].buffer = NULL; + } +} + +struct menu_T *file_menu_list(char *ext, void (*callback)(char *, int), + int offset, int *size) { char **buffer; int n; load_files(); - n = file_select("all", &buffer); + n = file_select("part", &buffer); - struct menu_T *file_items = malloc(n * sizeof(struct menu_T)); + struct menu_T *file_items = malloc((n + offset) * sizeof(struct menu_T)); for (int i = 0; i < n; i++) { - file_items[i].name = buffer[i]; - file_items[i].callback = load_file; + file_items[i + offset].name = buffer[i]; + file_items[i + offset].callback = callback; } free(buffer); - display_menu(wind, file_items, n); - mode_select(wind, "nothing", 0); + *size = n + offset; + return file_items; +} + +void save_pattern(void) { + int n; + struct menu_T *file_items = file_menu_list("part", file_save_pattern, 1, &n); + file_items[0].name = "NEW"; + file_items[0].callback = new_file; + display_menu(menu_w, "Save Pattern", file_items, n); free(file_items); - free_files(); } -void exitp(window_T wind, char *pass, int index) { +void load_pattern(void) { + int n; + struct menu_T *file_items = file_menu_list("part", file_load_pattern, 0, &n); + + display_menu(menu_w, "Load Pattern", file_items, n); + free(file_items); +} + +void load(char *pass, int index) { + int n; + struct menu_T *file_items = file_menu_list("part", file_load, 0, &n); + + display_menu(menu_w, "Load Game", file_items, n); + free(file_items); + + mode_select("nothing", 0); +} + +void exitp(char *pass, int index) { display_stop(); exit(0); } @@ -226,24 +331,26 @@ int state = 0; int main(void) { setlocale(LC_ALL, ""); - if (!display_start()) { - printf("Couldn't start the display!\n"); - } - if (!file_setup()) { printf("File setup error\n"); + abort(); } - status_w = window_split(MAIN_w, 1, 3, 0); - screen_w = window_sibiling(status_w); + if (!display_start()) { + printf("Couldn't start the display!\n"); + abort(); + } + menu_w = MAIN_w; while (TRUE) { - display_menu(screen_w, menu_items, menu_items_s); - window_clear(screen_w); + display_menu(menu_w, "Main menu", menu_items, menu_items_s); } + window_free(MAIN_w); + if (!display_stop()) { printf("Couldn't stop the display!\n"); + abort(); } return 0; diff --git a/src/window.c b/src/window.c @@ -21,17 +21,24 @@ struct T { int param[4]; int mod[3]; + + char *title; }; -void WINDOW_init(WINDOW *win) { +void WINDOW_init(WINDOW *win, char *title) { window_settings(win); + wattrset(win, COLOR_PAIR(0)); box(win, ACS_VLINE, ACS_HLINE); + if (title) { + mvwprintw(win, 0, 1, "%s", title); + } wrefresh(win); } -void WINDOW_new(T self) { - self->win = newwin(H(self), W(self), Y(self), X(self)); - WINDOW_init(self->win); +WINDOW *WINDOW_new(T self) { + WINDOW *win = newwin(H(self), W(self), Y(self), X(self)); + WINDOW_init(win, self->title); + return win; } T window_new(void) { @@ -40,6 +47,7 @@ T window_new(void) { self->c1 = NULL; self->c2 = NULL; self->sibiling = NULL; + self->title = NULL; H(self) = 0; W(self) = 0; Y(self) = 0; @@ -52,11 +60,11 @@ int window_height(T self) { return H(self) - 2; } int window_wight(T self) { return W(self) - 2; } WINDOW *window_win(T self) { return self->win; } -T window_init(T self) { +void window_set_title(T self, char *title) { self->title = title; } +T window_init(T self) { self->win = stdscr; - box(self->win, ACS_VLINE, ACS_HLINE); - wrefresh(self->win); + WINDOW_init(stdscr, self->title); H(self) = LINES; W(self) = COLS; return self; @@ -71,6 +79,13 @@ void window_free(T self) { free(self); } +void window_unsplit(T self) { + window_free(self->c1); + window_free(self->c2); + self->c1 = NULL; + self->c2 = NULL; +} + void window_calc_children(T self) { T c1, c2, f, nf; c1 = self->c1; @@ -129,7 +144,12 @@ void window_calc_children(T self) { } } -T window_split(T self, int hor, int a, int b) { +T window_split(T self, int hor, int a, int b, char *name1, char *name2) { + if (self->c1) + window_free(self->c1); + if (self->c2) + window_free(self->c2); + self->c1 = window_new(); self->c2 = window_new(); @@ -142,13 +162,16 @@ T window_split(T self, int hor, int a, int b) { window_calc_children(self); - WINDOW_new(self->c1); - WINDOW_new(self->c2); + self->c1->title = name1; + self->c2->title = name2; + + self->c1->win = WINDOW_new(self->c1); + self->c2->win = WINDOW_new(self->c2); return self->c1; } -T window_center(T self, int tmp, int h, int w) { +T window_center(T self, int tmp, int h, int w, char *name) { self->c1 = window_new(); self->c2 = NULL; @@ -157,7 +180,9 @@ T window_center(T self, int tmp, int h, int w) { self->mod[2] = w; window_calc_children(self); - WINDOW_new(self->c1); + + self->c1->title = name; + self->c1->win = WINDOW_new(self->c1); return self->c1; } @@ -169,19 +194,19 @@ void window_update_children(T self) { window_calc_children(self); delwin(self->c1->win); - WINDOW_new(self->c1); + self->c1->win = WINDOW_new(self->c1); window_update_children(self->c1); if (self->c2 != NULL) { delwin(self->c2->win); - WINDOW_new(self->c2); + self->c2->win = WINDOW_new(self->c2); window_update_children(self->c2); } } void window_clear(T self) { wclear(self->win); - WINDOW_init(self->win); + WINDOW_init(self->win, self->title); } void window_settings(WINDOW *win) { keypad(win, TRUE); }