gol

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

commitc48f5196f08e800160564302abbe978a6f6b26b2
parentb9104dd02549f3e28fd2be0fa526b77e2d505de7
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateThu, 16 Jun 2022 16: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|++++++-
Minclude/display.h|+
Minclude/window.h|+++++++++++++++++++--------------
Msrc/display.c|++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/file.c|+++++++++++
Msrc/game.c|+++++++++++++++++++++++++++---
Msrc/window.c|+++++++++++++++++++

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
*