commit 13229b25c4cd705fee1bccfeb14f626346ffcf42
parent dd16dc66dd4b3fccc27c3f9c4f71808eeaec0b7d
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Wed, 18 May 2022 20:33:42 +0200
Cleanup and Responsive application resize
- Contents of the main.c has been split into multiple files based on the role
- windows.c has been added to handle the window-splitting behavior
- All of the menus and the game itself are fully responsive in both
Linux and Windows
- All the menus have been tied together as well as streamlined to better
fit the task at hand
Diffstat:
A | include/display.h | | | 32 | ++++++++++++++++++++++++++++++++ |
A | include/file.h | | | 13 | +++++++++++++ |
A | include/utils.h | | | 22 | ++++++++++++++++++++++ |
A | include/window.h | | | 27 | +++++++++++++++++++++++++++ |
A | src/display.c | | | 214 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/file.c | | | 135 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/main.c | | | 439 | ++++++++++++++++++++----------------------------------------------------------- |
A | src/utils.c | | | 4 | ++++ |
A | src/window.c | | | 177 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
9 files changed, 735 insertions(+), 328 deletions(-)
diff --git a/include/display.h b/include/display.h
@@ -0,0 +1,32 @@
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#include "window.h"
+
+extern window_T MAIN_w;
+
+typedef int (*input_f)(int);
+
+struct menu_T {
+ void (*callback)(window_T, char *);
+ char *name;
+};
+
+struct imenu_T {
+ char *message;
+ int size;
+ input_f crit;
+ char *buffer;
+};
+
+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);
+int display_imenu(window_T wind, struct imenu_T *items, int size);
+
+void handle_winch(int sig);
+
+#endif
diff --git a/include/file.h b/include/file.h
@@ -0,0 +1,13 @@
+#ifndef FILE_H
+#define FILE_H
+
+#include "display.h"
+
+int file_setup(void);
+void load_files(void);
+void free_files(void);
+int file_select(char *ext, char ***buffer);
+
+void load_file(window_T win, char *pass);
+
+#endif
diff --git a/include/utils.h b/include/utils.h
@@ -0,0 +1,22 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <curses.h>
+
+#define MAX(a, b) ((a > b) ? a : b)
+#define MIN(a, b) ((a < b) ? a : b)
+#define CLAMP(a, x, y) (a = MAX(x, MIN(a, y)))
+
+#ifdef _WIN32
+#define is_term_resized(a, b) is_termresized()
+#define usleep(a) _sleep(0.5)
+#define HANDLE_RESIZE \
+ { \
+ resize_term(0, 0); \
+ handle_winch(10); \
+ goto redraw; \
+ }
+#else
+#define HANDLE_RESIZE goto redraw;
+#endif
+#endif
diff --git a/include/window.h b/include/window.h
@@ -0,0 +1,27 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <curses.h>
+
+#define window_T T
+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);
+void window_update_children(T self);
+
+T window_sibiling(T self);
+int window_height(T self);
+int window_wight(T self);
+WINDOW *window_win(T self);
+void window_settings(WINDOW *win);
+void window_clear(T self);
+
+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);
+
+#undef T
+#endif
diff --git a/src/display.c b/src/display.c
@@ -0,0 +1,214 @@
+#include <curses.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "display.h"
+#include "utils.h"
+#include "window.h"
+
+#define center_vertical(n) wcenter_vertical(MAIN_W, n);
+#define center_horizontal(y, n) wcenter_horizontal(MAIN_W, y, n);
+
+window_T MAIN_w = NULL;
+
+int input(WINDOW *win, char *buffer, int size, input_f crit) {
+ int CLINES = LINES, CCOLS = COLS;
+ int ch, read = strlen(buffer);
+
+ while ((ch = getch()) != '\n') {
+ switch (ch) {
+ case 27:
+ buffer[read] = '\0';
+ return 100;
+ case KEY_BACKSPACE:
+ case KEY_LEFT:
+ if (read > 0) {
+ cursor_offset(win, 0, -1);
+ wprintw(win, " ");
+ cursor_offset(win, 0, -1);
+ read--;
+ }
+ break;
+ case KEY_UP:
+ buffer[read] = '\0';
+ return -1;
+ case KEY_DOWN:
+ buffer[read] = '\0';
+ return +1;
+ default:
+ if (read < size && crit && crit(ch)) {
+ wprintw(win, "%c", ch);
+ buffer[read++] = ch;
+ }
+ break;
+ }
+ if (is_term_resized(CLINES, CCOLS)) {
+ buffer[read] = '\0';
+ return -100;
+ }
+ wrefresh(win);
+ }
+ buffer[read] = '\0';
+ return 0;
+}
+
+int display_imenu(window_T wind, struct imenu_T *items, int size) {
+ WINDOW *win;
+ int y_offset;
+ int current = 0;
+
+ for (int i = 0; i < size; i++)
+ items[i].buffer = calloc(5, sizeof(char));
+
+ int maxi = 0, len = 0;
+ for (int i = 0; i < size; i++)
+ if ((len = strlen(items[i].message)) > maxi)
+ maxi = len;
+
+ curs_set(1);
+ window_clear(wind);
+redraw:;
+ win = window_win(wind);
+ y_offset = wcenter_vertical(wind, size);
+
+ for (int i = 0; i < size; i++) {
+ wcenter_horizontal(wind, y_offset + 2 * i, 20);
+ wprintw(win, "%*s: %s", -maxi, items[i].message, items[i].buffer);
+ }
+ wrefresh(win);
+
+ while (TRUE) {
+ for (int i = 0; i < size; i++) {
+ if (current != i)
+ continue;
+
+ wcenter_horizontal(wind, y_offset + 2 * i, 20);
+ wprintw(win, "%*s: %s", -maxi, items[i].message, items[i].buffer);
+ switch (input(win, items[i].buffer, items[i].size, items[i].crit)) {
+ case -1:
+ current--;
+ break;
+ case 0:
+ if (++current == size) {
+ curs_set(0);
+ return 1;
+ }
+ break;
+ case 1:
+ current++;
+ break;
+ case 100:
+ curs_set(0);
+ return 0;
+ case -100:
+ HANDLE_RESIZE;
+ goto redraw;
+ }
+ CLAMP(current, 0, size - 1);
+ }
+ }
+
+ curs_set(0);
+}
+
+void display_menu(window_T wind, struct menu_T *items, int size) {
+ WINDOW *win;
+ int current = 0;
+
+ int maxi = 0, len = 0;
+ for (int i = 0; i < size; i++)
+ if ((len = strlen(items[i].name)) > maxi)
+ maxi = len;
+
+redraw:;
+ win = window_win(wind);
+ int CLINES = LINES, CCOLS = COLS;
+ int y_offset = wcenter_vertical(wind, size * 2);
+ while (TRUE) {
+ CLAMP(current, 0, size - 1);
+
+ for (int i = 0; i < size; i++) {
+ wattrset(win, COLOR_PAIR(i == current ? 1 : 0));
+ wcenter_horizontal(wind, y_offset + i * 2, maxi);
+ wprintw(win, "%s", items[i].name);
+ }
+ wrefresh(win);
+
+ while (TRUE) {
+ int c = getch();
+ if (c == 'k' || c == KEY_UP) {
+ current--;
+ break;
+ } else if (c == 'j' || c == KEY_DOWN) {
+ current++;
+ break;
+ } else if (c == '\n') {
+ wattrset(win, COLOR_PAIR(0));
+ window_clear(wind);
+ items[current].callback(wind, items[current].name);
+ /* window_clear(wind); */
+ return;
+ } else if (c == 27)
+ return;
+ if (is_term_resized(CLINES, CCOLS)) {
+ HANDLE_RESIZE;
+ goto redraw;
+ }
+ }
+ }
+}
+
+void curses_start(void) {
+ initscr();
+ start_color();
+ use_default_colors();
+
+ curs_set(0);
+ noecho();
+ nodelay(stdscr, 1);
+
+ window_settings(stdscr);
+
+ init_pair(0, COLOR_WHITE, -1);
+ init_pair(1, COLOR_RED, -1);
+
+ init_pair(2, COLOR_WHITE, COLOR_WHITE);
+ init_pair(3, COLOR_BLACK, -1);
+}
+
+void curses_stop(void) {
+ window_free(MAIN_w);
+ endwin();
+}
+
+void handle_winch(int sig) {
+ endwin();
+ refresh();
+ clear();
+
+ refresh();
+ window_init(MAIN_w);
+ window_update_children(MAIN_w);
+}
+
+int display_start(void) {
+#ifndef _WIN32
+ signal(SIGWINCH, handle_winch);
+#endif
+
+ curses_start();
+ MAIN_w = window_init(window_new());
+
+#ifdef _WIN32
+ resize_term(0, 0);
+ handle_winch(10);
+#endif
+
+ return 1;
+}
+
+int display_stop(void) {
+ curses_stop();
+ return 1;
+}
diff --git a/src/file.c b/src/file.c
@@ -0,0 +1,135 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "display.h"
+
+#ifdef _WIN32
+#define SETTINGS_DIR "C:\\GoL" // without trailing '\'
+#define MAKE_DIR(dir) (mkdir(dir))
+#else
+#define SETTINGS_DIR "/home/magaknuto/GoL"
+#define MAKE_DIR(dir) (mkdir(dir, 0777))
+#endif // _WIN32
+
+typedef struct file_T *file_T;
+struct file_T {
+ file_T next;
+ char *name;
+};
+
+file_T loaded_files;
+
+file_T file_new(char *name) {
+ file_T f;
+ f = malloc(sizeof(*f));
+ f->next = NULL;
+ if (name == NULL) {
+ f->name = NULL;
+ return f;
+ }
+
+ f->name = malloc((strlen(name) + 1) * sizeof(char));
+ strcpy(f->name, name);
+ return f;
+}
+
+void file_free(file_T self) {
+ if (self == NULL)
+ return;
+ file_free(self->next);
+ free(self->name);
+ free(self);
+}
+
+file_T file_add(file_T self, char *name) {
+ for (; self->next != NULL; self = self->next)
+ ;
+ self->next = file_new(name);
+ return self->next;
+}
+
+int DirectoryExists(const char *path) {
+ struct stat stats;
+ stat(path, &stats);
+
+ return S_ISDIR(stats.st_mode);
+}
+
+file_T file_fromDirectory(void) {
+ file_T base = file_new(NULL);
+
+ struct dirent *de;
+ DIR *dr = opendir(".");
+ if (dr == NULL)
+ return NULL;
+
+ while ((de = readdir(dr)) != NULL)
+ file_add(base, de->d_name);
+
+ file_T n = base->next;
+
+ free(base);
+ free(dr);
+
+ return n;
+}
+
+file_T file_find(file_T self, char *name) {
+ for (; self != NULL; self = self->next) {
+ if (!strcmp(self->name, name))
+ return self;
+ }
+ return NULL;
+}
+
+int file_setup(void) {
+ if (!DirectoryExists(SETTINGS_DIR)) {
+ if (MAKE_DIR(SETTINGS_DIR) != 0) {
+ return 0;
+ }
+ }
+
+ if (chdir(SETTINGS_DIR) != 0) {
+ return 0;
+ }
+ return 1;
+}
+
+int file_select(char *ext, char ***buffer) {
+ int maxsize = 4;
+ int size = 0;
+ char **tmp;
+ file_T current = loaded_files;
+
+ *buffer = malloc(maxsize * sizeof(char *));
+ for (; current != NULL; current = current->next) {
+ char *dot = strrchr(current->name, '.');
+ if (dot == NULL)
+ continue;
+ if (!strcmp(dot + 1, ext)) {
+ *dot = '\0';
+ (*buffer)[size++] = current->name;
+ if (size == maxsize) {
+ maxsize *= 2;
+ tmp = realloc(*buffer, maxsize * sizeof(char *));
+ if (!tmp)
+ exit(1);
+ *buffer = tmp;
+ }
+ }
+ }
+ tmp = realloc(*buffer, size * sizeof(char *));
+ if (!tmp)
+ exit(1);
+ *buffer = tmp;
+ return size;
+}
+
+void load_files(void) { loaded_files = file_fromDirectory(); }
+void free_files(void) { file_free(loaded_files); }
+void load_file(window_T win, char *pass) { (void)3; }
diff --git a/src/main.c b/src/main.c
@@ -1,234 +1,50 @@
// This is not a final version of the code
-// This is just a quick proof of concept
-// Many things need to be addressed later
+// While I've cleaned this file up,
+// all of the game logic is still here
#include <ctype.h>
#include <curses.h>
#include <locale.h>
-#include <signal.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <wchar.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
+#include "display.h"
+#include "file.h"
+#include "utils.h"
+#include "window.h"
+
+extern window_T MAIN_w;
WINDOW *game_w, *board_w, *status_w;
int top_space = 5;
-typedef struct file_T *file_T;
-struct file_T {
- file_T next;
- char *name;
-};
-
-file_T file_new(char *name) {
- file_T f;
- f = malloc(sizeof(*f));
- f->next = NULL;
- if (name == NULL) {
- f->name = NULL;
- return f;
- }
-
- f->name = malloc((strlen(name) + 1) * sizeof(char));
- strcpy(f->name, name);
- return f;
-}
-
-void file_free(file_T self) {
- if (self == NULL)
- return;
- file_free(self->next);
- free(self->name);
- free(self);
-}
-
-file_T file_add(file_T self, char *name) {
- for (; self->next != NULL; self = self->next)
- ;
- self->next = file_new(name);
- return self->next;
-}
-
-void file_list(file_T self) {
- for (; self != NULL; self = self->next)
- printw("%s ", self->name);
-}
-
-int DirectoryExists(const char *path) {
- struct stat stats;
- stat(path, &stats);
-
- return S_ISDIR(stats.st_mode);
-}
-
-file_T file_fromDirectory(void) {
- file_T base = file_new(NULL);
-
- struct dirent *de;
- DIR *dr = opendir(".");
- if (dr == NULL)
- return NULL;
-
- move(0, 0);
- while ((de = readdir(dr)) != NULL)
- file_add(base, de->d_name);
-
- file_T n = base->next;
-
- free(base);
- free(dr);
-
- return n;
-}
-
-file_T file_find(file_T self, char *name) {
- for (; self != NULL; self = self->next) {
- if (!strcmp(self->name, name))
- return self;
- }
- return NULL;
-}
-
-struct extension_T {
- char *ext;
- file_T list;
-};
-
-void file_filter(file_T self, struct extension_T *ext, int ext_s) {
- file_T *tmp = malloc(ext_s * sizeof(file_T));
- for (int i = 0; i < ext_s; i++) {
- tmp[i] = ext[i].list = file_new(NULL);
- }
-
- move(10, 0);
- for (; self != NULL; self = self->next) {
- char *dot = strrchr(self->name, '.');
- if (dot == NULL)
- continue;
- for (int i = 0; i < ext_s; i++) {
- if (!strcmp(ext[i].ext, dot)) {
- tmp[i] = tmp[i]->next = file_new(self->name);
- break;
- }
- }
- }
-
- for (int i = 0; i < ext_s; i++) {
- printw("\nExtension %s: ", ext[i].ext);
- file_T n = ext[i].list->next;
- free(ext[i].list);
- file_list(ext[i].list = n);
- }
- free(tmp);
-}
-
-#ifdef _WIN32
-#define WINDOWS 1
-#define UNIX 0
-#define SETTINGS_DIR "C:\\GoL" // without trailing '\'
-#define MAKE_DIR(dir) (mkdir(dir))
-#else
-#define WINDOWS 0
-#define UNIX 1
-#define SETTINGS_DIR "/home/magaknuto/GoL"
-#define MAKE_DIR(dir) (mkdir(dir, 0777))
-#endif // _WIN32
-
-void setup(char *pass) {
- if (!DirectoryExists(SETTINGS_DIR)) {
- printw("%s does not exist, trying to create it....\n", SETTINGS_DIR);
- if (MAKE_DIR(SETTINGS_DIR) != 0) {
- printw("Unfortunately, can't create a directory: %s", SETTINGS_DIR);
- getch();
- exit(1);
- }
- printw("Success!\n");
- } else
- printw("%s already exists\n", SETTINGS_DIR);
-
- if (chdir(SETTINGS_DIR) != 0) {
- printw("chdir(%s): not successfull!\n", SETTINGS_DIR);
- getch();
- exit(1);
- } else
- printw("Directory has successfully been changed to %s!\n", SETTINGS_DIR);
-}
-
-#define MAX(a, b) ((a > b) ? a : b)
-#define MIN(a, b) ((a < b) ? a : b)
-#define CLAMP(a, x, y) (a = MAX(x, MIN(a, y)))
-
-void cursor_offset(int oy, int ox) {
- int y, x;
- getyx(stdscr, y, x);
- move(y + oy, x + ox);
-}
-
-typedef int (*input_f)(int);
-void input(char *buffer, int size, input_f crit) {
- int ch;
- int read = 0;
- while ((ch = getch()) != '\n') {
- switch (ch) {
- case KEY_BACKSPACE:
- if (read > 0) {
- cursor_offset(0, -1);
- delch();
- read--;
- }
- default:
- if (read < size && crit && crit(ch)) {
- printw("%c", ch);
- buffer[read++] = ch;
- }
- }
- }
- printw("\n");
- buffer[read] = '\0';
-}
-
-void wcenter_horizontal(WINDOW *win, int y, int n) {
- int mx, my;
- getmaxyx(win, my, mx);
- wmove(win, y, (mx - n) / 2);
-}
+void show(window_T wind, unsigned **univ, int w, int h, int y, int x) {
+ WINDOW *win = window_win(wind);
+ wattrset(win, COLOR_PAIR(0));
-int wcenter_vertical(WINDOW *win, int n) {
- int mx, my;
- getmaxyx(win, my, mx);
- return (my - n) / 2;
-}
-#define center_vertical(n) wcenter_vertical(stdscr, n);
-#define center_horizontal(y, n) wcenter_horizontal(stdscr, y, n);
-
-void show(WINDOW *win, unsigned **univ, int w, int h, int y, int x) {
- attrset(COLOR_PAIR(0));
int ph = h, pw = w, mh, mw;
- getmaxyx(win, mh, mw);
+ mh = window_height(wind);
+ mw = window_wight(wind) / 2;
CLAMP(ph, 0, mh);
CLAMP(pw, 0, mw);
- int top = wcenter_vertical(win, ph);
+ int top = wcenter_vertical(wind, ph);
for (int i = 0; i < ph; i++) {
- wcenter_horizontal(win, top + i, pw);
+ wcenter_horizontal(wind, top + i, pw * 2);
for (int j = 0; j < pw; j++) {
#ifdef _WIN32
wattrset(win,
COLOR_PAIR((univ[(i + y + h) % h][(j + x + w) % w]) ? 2 : 3));
wprintw(win, " ");
#else
- /* if (univ[(i + y + h) % h][(j + x + w) % w]) */
- /* wprintw(win, "%lc", 0x2B1B); */
- /* else */
- /* wprintw(win, " ", 0x2B1C); */
if (univ[(i + y + h) % h][(j + x + w) % w])
- wprintw(win, "%lc", (wchar_t)L'\u2B1B');
+ wprintw(win, "%lc ", (wchar_t)L'\u23FA');
else
- wprintw(win, " ", (wchar_t)L'\u2B1C');
+ wprintw(win, " ");
+ /* wprintw(win, "%lc", (wchar_t)L'\u2B1B'); */
+ /* wprintw(win, " ", (wchar_t)L'\u2B1C'); */
#endif
}
}
@@ -262,20 +78,10 @@ void evolve(unsigned **univ, unsigned **new, int w, int h, int step) {
univ[i][j] = new[i][j];
}
-void game(int w, int h) {
- clear();
- box(stdscr, ACS_VLINE, ACS_HLINE);
- refresh();
-
- box(game_w, ACS_VLINE, ACS_HLINE);
- wrefresh(game_w);
-
- box(status_w, ACS_VLINE, ACS_HLINE);
- wbkgd(status_w, '.');
- wrefresh(status_w);
-
- if (!w || !h) {
- getmaxyx(board_w, h, w);
+void game(window_T wind, int w, int h) {
+ if (w <= 0 || h <= 0) {
+ h = window_height(wind);
+ w = window_wight(wind);
w /= 2;
}
@@ -292,16 +98,19 @@ void game(int w, int h) {
new[i] = malloc(w * sizeof(unsigned));
}
- nodelay(status_w, 1);
- keypad(status_w, TRUE);
int oy = 0, ox = 0;
int in = 3;
int gen_step = 1;
- while (1) {
- show(board_w, univ, w, h, oy, ox);
+
+ window_clear(wind);
+redraw:;
+ /* window_clear(wind); */
+ int CLINES = LINES, CCOLS = COLS;
+ while (TRUE) {
+ show(wind, univ, w, h, oy, ox);
evolve(univ, new, w, h, gen_step);
for (int i = 0; i < in; i++) {
- int c = wgetch(status_w);
+ int c = getch();
switch (c) {
case KEY_A1:
case KEY_C1:
@@ -332,138 +141,112 @@ void game(int w, int h) {
case KEY_END:
case KEY_NPAGE:
oy++;
- break;
+ }
+ break;
+ switch (c) {
+ case 27:
+ return;
}
}
ox = (ox + w) % w;
oy = (oy + h) % h;
+
flushinp();
- usleep(150000);
+
+ usleep(200000);
+ if (is_term_resized(CLINES, CCOLS)) {
+ HANDLE_RESIZE;
+ goto redraw;
+ }
}
}
-void start(char *pass) {
- char buffer[100];
- int row, column;
- printw("Unesi broj redova: ");
- input(buffer, 4, isdigit);
- row = atoi(buffer);
- printw("Unesi broj kolona: ");
- input(buffer, 4, isdigit);
- column = atoi(buffer);
- game(row, column);
- refresh();
-}
+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 load(char *pass) {
- printw("Load\n");
- getch();
-}
+void settings(window_T wind, char *pass) {
+ if (display_imenu(wind, imenu_items, imenu_items_s)) {
+ int row = atoi(imenu_items[0].buffer);
+ int column = atoi(imenu_items[1].buffer);
+ game(wind, row, column);
+ }
-void exitp(char *pass) {
- endwin();
- exit(0);
+ for (int i = 0; i < imenu_items_s; i++)
+ free(imenu_items[i].buffer);
}
-struct extension_T ext[] = {
- { ".c", NULL},
- { ".h", NULL},
- {".part", NULL},
- { ".all", NULL}
-};
-int ext_s = sizeof(ext) / sizeof(struct extension_T);
-
-void list(char *pass) {
- file_T files = file_fromDirectory();
- file_filter(files, ext, ext_s);
- for (int i = 0; i < ext_s; i++)
- file_free(ext[i].list);
- file_free(files);
-}
+void load(window_T wind, char *pass) {
+ char **buffer;
+ int n;
-struct menu_T {
- void (*callback)(char *);
- char *name;
-};
+ load_files();
+ n = file_select("all", &buffer);
-struct menu_T menu_items[] = {
- {start, "Start"},
- {setup, "Setup"},
- { list, "List"},
- { load, "Load"},
- {exitp, "Exit"}
-};
-int menu_items_s = sizeof(menu_items) / sizeof(struct menu_T);
-
-void display_menu(struct menu_T *items, int size) {
- int current = 0;
+ struct menu_T *file_items = malloc(n * sizeof(struct menu_T));
+ for (int i = 0; i < n; i++) {
+ file_items[i].name = buffer[i];
+ file_items[i].callback = load_file;
+ }
+ free(buffer);
- int *lens = malloc(size * sizeof(int));
- for (int i = 0; i < size; i++)
- lens[i] = strlen(items[i].name);
+ display_menu(wind, file_items, n);
+ game(wind, 0, 0);
- int y_offset = center_vertical(size * 2);
- while (TRUE) {
- CLAMP(current, 0, size - 1);
- for (int i = 0; i < size; i++) {
- attrset(COLOR_PAIR(i == current ? 1 : 0));
- center_horizontal(y_offset + i * 2, lens[i]);
- printw("%s", items[i].name);
- }
- refresh();
- switch (getch()) {
- case 'k':
- case KEY_UP:
- current--;
- break;
- case KEY_DOWN:
- case 'j':
- current++;
- break;
- case '\n':
- move(16, 0);
- attrset(COLOR_PAIR(0));
- items[current].callback(NULL);
- }
- }
- free(lens);
+ free(file_items);
+ free_files();
}
-void ncurses_window_setup(void) {
- game_w = newwin(LINES - 2 - top_space, COLS - 4, 1 + top_space, 2);
- board_w = newwin(LINES - 4 - top_space, COLS - 6, 2 + top_space, 3);
- status_w = newwin(top_space, COLS - 4, 1, 2);
+void exitp(window_T wind, char *pass) {
+ display_stop();
+ exit(0);
}
-void ncurses_window_end(void) {
- delwin(game_w);
- delwin(board_w);
- delwin(status_w);
-}
+struct menu_T mode_items[] = {
+ {settings, "Normalan"},
+ {settings, "Koegzistencija"},
+ {settings, "Predator i pljen"},
+ {settings, "Virus"},
+ {settings, "Nepoznanost"},
+};
+int mode_items_s = sizeof(mode_items) / sizeof(struct menu_T);
-void ncurses_start(void) {
- initscr();
- start_color();
- use_default_colors();
- curs_set(0);
- noecho();
- keypad(stdscr, TRUE);
- init_pair(0, COLOR_WHITE, -1);
- init_pair(1, COLOR_RED, -1);
-
- init_pair(2, COLOR_WHITE, COLOR_WHITE);
- init_pair(3, COLOR_BLACK, -1);
+void mode_select(window_T wind, char *pass) {
+ display_menu(wind, mode_items, mode_items_s);
}
+struct menu_T menu_items[] = {
+ {mode_select, "Start"},
+ { load, "Load"},
+ { exitp, "Exit"}
+};
+int menu_items_s = sizeof(menu_items) / sizeof(struct menu_T);
+
+int state = 0;
+
int main(void) {
setlocale(LC_ALL, "");
- ncurses_start();
- ncurses_window_setup();
+ if (!display_start()) {
+ printf("Couldn't start the display!\n");
+ }
+ if (!file_setup()) {
+ printf("File setup error\n");
+ }
+
+ T t1, t2;
+ t1 = window_split(MAIN_w, 1, 5, 0);
+ t2 = window_sibiling(t1);
- display_menu(menu_items, menu_items_s);
- getch();
+ while (TRUE) {
+ display_menu(t2, menu_items, menu_items_s);
+ window_clear(t2);
+ }
- endwin();
+ if (!display_stop()) {
+ printf("Couldn't stop the display!\n");
+ }
return 0;
}
diff --git a/src/utils.c b/src/utils.c
@@ -0,0 +1,4 @@
+#include <curses.h>
+
+#include "utils.h"
+
diff --git a/src/window.c b/src/window.c
@@ -0,0 +1,177 @@
+#include <curses.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "window.h"
+
+#define H(c) c->param[0]
+#define W(c) c->param[1]
+#define Y(c) c->param[2]
+#define X(c) c->param[3]
+
+#define window_T T
+typedef struct T *T;
+
+struct T {
+ WINDOW *win;
+ T c1;
+ T c2;
+ T sibiling;
+
+ int param[4];
+ int mod[3];
+};
+
+void WINDOW_init(WINDOW *win) {
+ window_settings(win);
+ box(win, ACS_VLINE, ACS_HLINE);
+ wrefresh(win);
+}
+
+void WINDOW_new(T self) {
+ self->win = newwin(H(self), W(self), Y(self), X(self));
+ WINDOW_init(self->win);
+}
+
+T window_new(void) {
+ T self = malloc(sizeof(*self));
+ self->win = NULL;
+ self->c1 = NULL;
+ self->c2 = NULL;
+ self->sibiling = NULL;
+ H(self) = 0;
+ W(self) = 0;
+ Y(self) = 0;
+ X(self) = 0;
+ return self;
+}
+
+T window_sibiling(T self) { return self->sibiling; }
+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) {
+ self->win = stdscr;
+ box(self->win, ACS_VLINE, ACS_HLINE);
+ wrefresh(self->win);
+ H(self) = LINES;
+ W(self) = COLS;
+ return self;
+}
+
+void window_free(T self) {
+ if (self == NULL)
+ return;
+ window_free(self->c1);
+ window_free(self->c2);
+ delwin(self->win);
+ free(self);
+}
+
+void window_calc(T self) {
+ T c1, c2, f, nf;
+ c1 = self->c1;
+ c2 = self->c2;
+ int fixed = 0, *fv;
+ int hor = self->mod[0], a = self->mod[1], b = self->mod[2];
+
+ if (a == 0 && b == 0)
+ return;
+
+ if (a == 0) {
+ f = c2;
+ nf = c1;
+ fv = &b;
+ fixed = 1;
+ } else if (b == 0) {
+ f = c1;
+ nf = c2;
+ fv = &a;
+ fixed = 1;
+ }
+
+ if (hor) {
+ W(c1) = W(c2) = W(self) - 2;
+
+ if (!fixed) {
+ H(c1) = ((H(self) - 2) / (a + b)) * a;
+ } else {
+ H(f) = *fv;
+ }
+ H(nf) = (H(self) - 2) - H(f);
+
+ X(c1) = X(c2) = X(self) + 1;
+ Y(c1) = Y(self) + 1;
+ Y(c2) = Y(self) + H(c1) + 1;
+ } else {
+ H(c1) = H(c2) = H(self) - 2;
+
+ if (!fixed) {
+ W(c1) = ((W(self) - 2) / (a + b)) * a;
+ } else {
+ W(f) = *fv;
+ }
+ W(nf) = (W(self) - 2) - W(f);
+
+ Y(c1) = Y(c2) = Y(self) + 1;
+ X(c1) = X(self) + 1;
+ X(c2) = X(self) + W(c1) + 1;
+ }
+}
+
+T window_split(T self, int hor, int a, int b) {
+ self->c1 = window_new();
+ self->c2 = window_new();
+
+ self->c1 = window_new();
+ self->c2 = window_new();
+
+ self->c1->sibiling = self->c2;
+ self->c2->sibiling = self->c1;
+
+ self->mod[0] = hor;
+ self->mod[1] = a;
+ self->mod[2] = b;
+
+ window_calc(self);
+
+ WINDOW_new(self->c1);
+ WINDOW_new(self->c2);
+
+ return self->c1;
+}
+
+void window_update_children(T self) {
+ if (self == NULL || self->c1 == NULL || self->c2 == NULL)
+ return;
+
+ delwin(self->c1->win);
+ delwin(self->c2->win);
+ window_calc(self);
+ WINDOW_new(self->c1);
+ WINDOW_new(self->c2);
+ window_update_children(self->c1);
+ window_update_children(self->c2);
+}
+
+void window_clear(T self) {
+ wclear(self->win);
+ WINDOW_init(self->win);
+}
+
+void window_settings(WINDOW *win) { keypad(win, TRUE); }
+
+void wcenter_horizontal(T window, int y, int n) {
+ wmove(window_win(window), y, (W(window) - n - 2) / 2 + 1);
+}
+
+int wcenter_vertical(T window, int n) { return (H(window) - n - 2) / 2 + 1; }
+
+void cursor_offset(WINDOW *win, int oy, int ox) {
+ int y, x;
+ getyx(win, y, x);
+ wmove(win, y + oy, x + ox);
+}
+
+#undef T