gol

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

commit c48f5196f08e800160564302abbe978a6f6b26b2
parent b9104dd02549f3e28fd2be0fa526b77e2d505de7
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Thu, 16 Jun 2022 18:52:03 +0200

Improved long menus and mouse support

- Add support for mouse toggling cells
- Add NO_MOUSE flag to Makefile to disable mouse support
- Add scrolling feature to long menus
- Sorting file lists

Diffstat:
MMakefile | 7++++++-
Minclude/display.h | 1+
Minclude/window.h | 33+++++++++++++++++++--------------
Msrc/display.c | 61++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/file.c | 11+++++++++++
Msrc/game.c | 30+++++++++++++++++++++++++++---
Msrc/window.c | 19+++++++++++++++++++
7 files changed, 133 insertions(+), 29 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ # GNU Makefile for Game of Life simulation # -# Usage: make [-f path\Makefile] [DEBUG=Y] [NO_UNICODE=Y] target +# Usage: make [-f path\Makefile] [DEBUG=Y] [NO_UNICODE=Y] [NO_MOUSE=Y] target NAME = gol CC = gcc @@ -35,6 +35,10 @@ ifeq ($(NO_UNICODE),Y) CFLAGS += -D NO_UNICODE endif +ifeq ($(NO_MOUSE),Y) + CFLAGS += -D NO_MOUSE +endif + all: $(BIN) $(BIN): $(OBJS) @@ -64,6 +68,7 @@ help: @echo "Optional parameters:" @echo " DEBUG - Compile binary file with debug flags enabled" @echo " NO_UNICODE - Compile binary file that does not use Unicode characters" + @echo " NO_MOUSE - Compile binary file that does not have mouse support even if terminal supports it" @echo .PHONY: all clean help docs diff --git a/include/display.h b/include/display.h @@ -20,6 +20,7 @@ #endif extern window_T MAIN_w; +extern mmask_t mbitmask; typedef int (*input_f)(int); diff --git a/include/window.h b/include/window.h @@ -8,27 +8,32 @@ typedef struct T *T; // General -T window_new(void); -T window_init(T self); -T window_split(T self, int hor, int a, int b, char *name1, char *name2); -T window_center(T self, int h, int w, char *name); +T window_new(void); +T window_init(T self); +T window_split(T self, int hor, int a, int b, char *name1, char *name2); +T window_center(T self, int h, int w, char *name); WINDOW *window_win_new(T self); -void window_clear(T self); -void window_clear_noRefresh(T self); -void window_free(T self); -void window_settings(WINDOW *win); -void window_unsplit(T self); -void window_update_children(T self); +int window_clicked(T self, int y, int x); +void window_clear(T self); +void window_clear_noRefresh(T self); +void window_free(T self); +void window_settings(WINDOW *win); +void window_unsplit(T self); +void window_update_children(T self); // Setters and Gettern -T window_sibiling(T self); +T window_sibiling(T self); + WINDOW *window_win(T self); -int window_height(T self); -int window_wight(T self); -void window_set_title(T self, char *title); + +int window_height(T self); +int window_wight(T self); +int window_x(T self); +int window_y(T self); +void window_set_title(T self, char *title); // Help diff --git a/src/display.c b/src/display.c @@ -21,6 +21,7 @@ #include "window.h" window_T MAIN_w = NULL; +mmask_t mbitmask; /** * @brief Offset the cursor for ncurses WINDOW* @@ -107,8 +108,8 @@ int input(WINDOW *win, char *buffer, int size, input_f crit) { } /** - * @brief Given a array of struct imenu_T, display a menu where user will enter all of - * the information required from the array + * @brief Given a array of struct imenu_T, display a menu where user will enter + * all of the information required from the array */ int display_imenu(window_T wind, struct imenu_T *items, int size) { WINDOW *win; @@ -171,7 +172,8 @@ redraw:; } /** - * @brief Display the title of the game in the center of the screen if it can fit + * @brief Display the title of the game in the center of the screen if it can + * fit */ void display_title(window_T wind, int y) { WINDOW *win = window_win(wind); @@ -195,6 +197,9 @@ void display_menu(window_T wind, char *name, struct menu_T *items, int size, WINDOW *win; int current = 0; + char sep[] = ">--------<"; + int sep_len = strlen(sep); + int maxi = 0, len = 0; for (int i = 0; i < size; i++) if ((len = strlen(items[i].name)) > maxi) @@ -203,16 +208,31 @@ void display_menu(window_T wind, char *name, struct menu_T *items, int size, window_set_title(wind, name); window_clear_noRefresh(wind); + int d_start, d_size, y_offset; + + d_start = 0; redraw:; - win = window_win(wind); int CLINES = LINES, CCOLS = COLS; - int y_offset = wcenter_vertical(wind, size * 2 - 1); + win = window_win(wind); - if (title) - display_title(wind, title); + d_size = window_height(wind) / 2 - 2; + + CLAMP(d_size, 0, size); + y_offset = wcenter_vertical(wind, d_size * 2) + 1; while (TRUE) { - CLAMP(current, 0, size - 1); + window_clear(wind); + if (title) + display_title(wind, title); + + if (current == -1) + d_start--; + + if (current == d_size) + d_start++; + + CLAMP(d_start, 0, size - d_size); + CLAMP(current, 0, d_size - 1); if (!size) { char *message = "NOTHING TO DISPLAY HERE!"; @@ -225,11 +245,25 @@ redraw:; return; } - for (int i = 0; i < size; i++) { + if (d_size < size && d_start == 0) { + wattrset(win, COLOR_PAIR(0)); + wcenter_horizontal(wind, y_offset - 1, sep_len); + wprintw(win, "%s", sep); + } + + int index = d_start; + for (int i = 0; i < d_size; i++, index++) { wattrset(win, COLOR_PAIR(i == current ? 1 : 0)); wcenter_horizontal(wind, y_offset + i * 2, maxi); - wprintw(win, "%s", items[i].name); + wprintw(win, "%s", items[index].name); + } + + if (d_size < size && d_start == size - d_size) { + wattrset(win, COLOR_PAIR(0)); + wcenter_horizontal(wind, y_offset + d_size * 2 - 1, sep_len); + wprintw(win, "%s", sep); } + wrefresh(win); while (TRUE) { @@ -241,8 +275,9 @@ redraw:; current++; break; } else if (c == '\n') { + int index = d_start + current; wattrset(win, COLOR_PAIR(0)); - items[current].callback(items[current].name, current); + items[index].callback(items[index].name, index); return; } else if (c == 27) { flushinp(); @@ -299,6 +334,10 @@ void curses_start(void) { init_pair(9, COLOR_WHITE, COLOR_BLUE); init_pair(10, COLOR_RED, COLOR_BLACK); #endif + +#if defined NCURSES_MOUSE_VERSION && !defined NO_MOUSE + mbitmask = mousemask(BUTTON1_CLICKED, NULL); +#endif } /** diff --git a/src/file.c b/src/file.c @@ -64,6 +64,16 @@ int DirectoryExists(const char *path) { return S_ISDIR(stats.st_mode); } +void file_sort(file_T self) { + for (file_T p = self->next; p; p = p->next) + for (file_T t = p->next; t; t = t->next) + if (strcmp(p->name, t->name) > 0) { + char *tmp = p->name; + p->name = t->name; + t->name = tmp; + } +} + file_T file_fromDirectory(void) { file_T base = file_new(NULL); @@ -75,6 +85,7 @@ file_T file_fromDirectory(void) { while ((de = readdir(dr)) != NULL) file_add(base, de->d_name); + file_sort(base); file_T n = base->next; free(base); diff --git a/src/game.c b/src/game.c @@ -14,10 +14,12 @@ #define TIME_MOD 1000 #endif -extern char *evolution_names[]; -extern int evolution_cells[]; -extern int evolution_size; +extern char *evolution_names[]; +extern int evolution_cells[]; +extern int evolution_size; + extern window_T menu_w; +extern mmask_t mbitmask; extern Cell *hash; typedef int (*coordinate_f)(int, int, int); @@ -275,6 +277,7 @@ reset_screen: redraw:; int CLINES = LINES, CCOLS = COLS; clock_t start_t, end_t = 0, total_t; + MEVENT mort; if (!wrap) { game_w = window_center(screen_w, window_height(screen_w), @@ -400,6 +403,27 @@ redraw:; cursor_change = 1; break; +#if defined NCURSES_MOUSE_VERSION && !defined NO_MOUSE + // mouse toggle cell + case KEY_MOUSE: + getmouse(&mort); + if (!window_clicked(game_w, mort.y, mort.x)) + break; + + int mouse_offset_y = mort.y - window_y(game_w) - 1; + int mouse_offset_x = (mort.x - window_x(game_w) - 1) / 2; + int val = + toggleAt(cord(y_at(mouse_offset_y)), cord(x_at(mouse_offset_x))); + + if (mouse_offset_x != cursor_offset_x || + mouse_offset_y != cursor_offset_y) { + mvprint_cell(game_W, mouse_offset_y, mouse_offset_x, 2, CHAR_BLANK); + wrefresh(game_W); + } else + cursor_change = 1; + break; +#endif + // toggle cell case ' ': toggleAt(cord(y_at(cursor_offset_y)), cord(x_at(cursor_offset_x))); diff --git a/src/window.c b/src/window.c @@ -89,6 +89,12 @@ int window_height(T self) { return H(self) - 2; } /// Getter: return the width of a current window int window_wight(T self) { return W(self) - 2; } +/// Getter: return the x coordinate of the current window +int window_x(T self) { return X(self); } + +/// Getter: return the y coordinate of the current window +int window_y(T self) { return Y(self); } + /// Getter: return the ncurses WINDOW* of the current window WINDOW *window_win(T self) { return self->win; } @@ -337,6 +343,19 @@ void window_settings(WINDOW *win) { } /** + * @brief Check if cordinates are in the window + */ +int window_clicked(T self, int y, int x) { + if (x <= X(self) || y <= Y(self)) + return 0; + + if (x >= X(self) + W(self) || y >= Y(self) + H(self)) + return 0; + + return 1; +} + +/** * @brief Move the cursor to the given why position and x position so that the * text of len n will be centered *