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:
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
*