Intial commit
[simple-cellular-automata-suite.git] / driver.c
blob73904b9b6fbd852da775f5c431cf84f57a0ce178
1 #include <locale.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <ncurses.h>
6 #include "engine.h"
8 #define FPS_CAP 10
9 #define E_BAD_FILE 1
10 #define E_BAD_SCREEN_DIMS 2
11 #define E_ENGINE_INITIALIZE 3
12 #define E_ENGINE_ERROR 4
13 #define E_USAGE 9
15 static int err;
17 int inp_cell(int height, int width, int s_height, int s_width, int yoff,
18 int xoff)
20 int i, j;
21 static int x = -1, y = -1;
22 int c;
24 int n = 0;
25 const char * const *titles = NULL;
26 char **values;
28 if (x < 1)
29 x = width / 2;
30 if (y < 1)
31 y = height / 2;
33 if (con_input_titles(&n, &titles))
34 return 1;
36 values = calloc(n, sizeof(*values));
38 move(s_height, 0);
39 for (j = 0; j < s_width; ++j)
40 addch(' ');
42 mvaddstr(s_height, 0, "Select:");
43 refresh();
45 curs_set(1);
47 do {
49 if (x < 0)
50 x = 0;
51 else if (x >= width)
52 x = width - 1;
53 if (y < 0)
54 y = 0;
55 else if (y >= height)
56 y = height - 1;
58 move(yoff + y, xoff + x);
60 c = getch();
61 switch(c) {
62 case 'h': case KEY_LEFT: x--; break;
63 case 'l': case KEY_RIGHT: x++; break;
64 case 'j': case KEY_DOWN: y++; break;
65 case 'k': case KEY_UP: y--; break;
66 case 'y': case KEY_A1: x--; y--; break;
67 case 'u': case KEY_A3: x++; y--; break;
68 case 'b': case KEY_C1: x--; y++; break;
69 case 'n': case KEY_C3: x++; y++; break;
70 case 'H': x-=8; break;
71 case 'L': x+=8; break;
72 case 'J': y+=8; break;
73 case 'K': y-=8; break;
74 case 'Y': x-=8; y-=8; break;
75 case 'U': x+=8; y-=8; break;
76 case 'B': x-=8; y+=8; break;
77 case 'N': x+=8; y+=8; break;
80 } while(c != ' ' && c != '\n' && c != '\r' && c != KEY_ENTER);
82 for (i = 0; i < n; ++i) {
83 values[i] = calloc(128, sizeof(*values[i]));
84 move(s_height, 0);
85 for (j = 0; j < s_width; ++j)
86 addch(' ');
87 mvaddstr(s_height, 0, titles[i]);
88 addstr(" ");
89 refresh();
90 echo();
91 nocbreak();
92 timeout(-1);
93 getstr(values[i]);
94 noecho();
95 cbreak();
96 timeout(1000 / FPS_CAP);
99 err = con_set_val(x, y, (const char **)values);
101 for (i = 0; i < n; ++i)
102 free(values[n]);
103 free(values);
105 curs_set(0);
106 return !err;
109 void bottom_bar(int height, int width, char run)
111 int i;
113 move(height, 0);
114 for (i = 0; i < width; ++i)
115 addch(' ');
116 move(height, 0);
118 addstr("[ ");
119 if (run) {
120 addstr("Running (");
121 addch('P' | A_STANDOUT);
122 addstr("ause) ] ");
123 } else {
124 addstr("Paused (");
125 addch('R' | A_STANDOUT);
126 addstr("un, ");
127 addch('S' | A_STANDOUT);
128 addstr("tep) ] ");
130 addstr("[ Set ");
131 addch('V' | A_STANDOUT);
132 addstr("alue ] [");
133 addch('Q' | A_STANDOUT);
134 addstr("uit ]");
135 refresh();
138 int displayloop(void)
140 int s_width = -1, s_height = -1, o_width = -1, o_height = -1;
141 int sx = -1, sy = -1;
142 int c = 0, i, j;
143 int g_width = con_width(), g_height = con_height();
144 char run = 0, should_quit = 0, onestep = 0, skip_this_calc = 0;
146 const char *cell = NULL;
148 do {
149 onestep = 0;
150 getmaxyx(stdscr, s_height, s_width);
151 s_height--;
153 if (s_height != o_height || s_width != o_width) {
154 clear();
155 refresh();
156 o_height = s_height;
157 o_width = s_width;
159 sy = (s_height - g_height - 1) / 2;
160 sx = (s_width - g_width - 1) / 2;
162 if (sy < 0 || sx < 0)
163 return E_BAD_SCREEN_DIMS;
165 if (sy > 0) {
166 if (sx > 0)
167 mvaddch((sy - 1), (sx - 1), ACS_ULCORNER);
169 move((sy - 1), sx); for (i = 0; i < g_width; ++i) addch(ACS_HLINE);
171 if (sx + g_width < s_width)
172 mvaddch((sy - 1), (sx + g_width), ACS_URCORNER);
175 if (sx > 0)
176 for (i = sy; i < sy + g_height; ++i)
177 mvaddch(i, (sx - 1), ACS_VLINE);
179 if (sx + g_width < s_width)
180 for (i = sy; i < sy + g_height; ++i)
181 mvaddch(i, (sx + g_width), ACS_VLINE);
183 if (sy + g_height < s_height) {
184 if (sx > 0)
185 mvaddch((sy + g_height), (sx - 1), ACS_LLCORNER);
187 move((sy + g_height), sx);
188 for (i = 0; i < g_width; ++i) addch(ACS_HLINE);
190 if (sx + g_width < s_width)
191 mvaddch((sy + g_height), (sx + g_width), ACS_LRCORNER);
195 for (j = 0; j < g_height; ++j) {
196 move(sy + j, sx);
197 for (i = 0; i < g_width; ++i) {
198 if ((err = con_rep_at(i, j, &cell)))
199 break;
200 addstr(cell);
204 do {
205 bottom_bar(s_height, s_width, run);
207 c = getch();
208 switch(c) {
209 case KEY_EXIT:
210 case 'Q':
211 case 'q': should_quit = 1; break;
212 case 'R':
213 case 'r': run = 1; break;
214 case 'P':
215 case 'p': run = 0; onestep = 0; break;
216 case ' ':
217 case 'S':
218 case 's': run = 0; onestep = 1; break;
219 case 'V':
220 case 'v':
221 run = 0;
222 onestep = 1;
223 skip_this_calc = 1;
224 inp_cell(g_height, g_width, s_height, s_width, sy, sx);
225 break;
226 case KEY_RESIZE:
227 run = 0; onestep = 1; skip_this_calc = 1; break;
229 } while (!(run || onestep) && !should_quit && !err);
231 if (should_quit || err)
232 break;
234 if (skip_this_calc)
235 skip_this_calc = 0;
236 else if ((err = con_step()))
237 break;
239 } while (!should_quit);
241 return (!err) ? 0 : E_ENGINE_ERROR;
244 int main(int argc, const char **argv)
246 int width = -1, height = -1, ret = 0;
247 FILE *template = NULL;
249 setlocale(LC_ALL, "");
251 if (argc == 2) {
252 if (!(template = fopen(argv[1], "r"))) {
253 perror("Could not open template file");
254 return E_BAD_FILE;
256 err = con_initialize_f(template);
257 fclose(template);
258 } else if (argc != 1) {
259 fprintf(stderr, "Usage: %s [path-to-input-file]\n", argv[0]);
260 return E_USAGE;
263 if (!initscr())
264 return -1;
265 getmaxyx(stdscr, height, width);
266 cbreak();
267 noecho();
268 curs_set(0);
269 timeout(1000 / FPS_CAP);
270 clear();
271 nonl();
272 intrflush(stdscr, FALSE);
273 keypad(stdscr, TRUE);
275 if (argc == 1)
276 err = con_initialize_wh(width, height - 1);
278 if (err) {
279 endwin();
280 fprintf(stderr, "Could not initialize engine: %s\n", con_errstring(err));
281 return E_ENGINE_INITIALIZE;
284 ret = displayloop();
285 endwin();
287 switch (ret) {
288 case E_BAD_SCREEN_DIMS:
289 fprintf(stderr, "Term dimensions too small.\n");
290 break;
291 case E_ENGINE_ERROR:
292 fprintf(stderr, "Engine error: %s\n", con_errstring(err));
293 break;
296 con_teardown();
298 return ret;