home · contact · privacy
Made keybindings array into linked list; on the way rewrote / improved great parts...
[plomrogue] / src / wincontrol.c
1 /* wincontrol.c */
2
3 #include "wincontrol.h"
4 #include <stdlib.h> /* for free() */
5 #include <string.h> /* for strlen(), strchr(), strstr() */
6 #include <stdint.h> /* for uint8_t, uint16_t */
7 #include <unistd.h> /* for access(), unlink() */
8 #include "windows.h" /* for suspend_win(), append_win(), reset_pad_offset(),
9                       * resize_active_win(), init_win(), free_win(),
10                       * structs Win, WinMeta
11                       */
12 #include "yx_uint16.h" /* for yx_uint16 struct */
13 #include "main.h" /* for Wins struct */
14 #include "readwrite.h" /* for get_linemax(), try_fopen(), try_fclose(),
15                         * try_fgets(), try_fclose_unlink_rename(), try_fwrite()
16                         */
17 #include "rexit.h" /* for exit_err() */
18 #include "main.h" /* for World, Wins structs */
19 #include "draw_wins.h" /* for draw_keys_win(), draw_info_win(), draw_log_win(),
20                         * draw_map_win
21                         */
22 #include "misc.h" /* for try_malloc() */
23 #include "dirent.h" /* for opendir(), closedir(), readdir() */
24 #include "errno.h" /* for errno */
25
26
27
28 /* Return string "prefix" + "id"; malloc()'s string, remember to call free()! */
29 static char * string_prefixed_id(struct World * world, char * prefix, char id);
30
31
32
33 /* Create Winconf, init ->view/height_type/width_type to 0, ->id to "id". */
34 static void create_winconf(char id, struct WinConf * wcp);
35
36 /* Initialize Winconf of "id" from appropriate config file.*/
37 static void init_winconf_from_file(struct World * world, char id);
38
39 /* Wrapper around init_win() called with values from Winconf of "id". */
40 static void init_win_from_winconf(struct World * world, char id);
41
42 /* Save title, draw function, size of window identified by "id" to conffile. */
43 static void save_win_config(struct World * world, char id);
44
45
46
47 /* Write size of a window to its WinConf, as positive or negative values
48  * (dependent on state ofWinConf->height_type / WinConf->width_type).
49  */
50 static void set_winconf(struct World * world, char id);
51
52
53
54 /* Get WinConf by "id"; get id of WinConf mothering "win". */
55 static struct WinConf * get_winconf_by_id(struct World * world, char id);
56
57 /* Get (Win->draw) function identified by "c"; NULL if c not mapped to one. */
58 static void * get_drawfunc_by_char(char c);
59
60 /* Iterate over bytes of world->winconf_ids array. Re-start after null byte. */
61 static char get_next_winconf_id(struct World * world);
62
63
64
65 static char * string_prefixed_id(struct World * world, char * prefix, char id)
66 {
67     uint8_t size = strlen(prefix) + 2;
68     char * path = try_malloc(size, world, "string_prefixed_id()");
69     sprintf(path, "%s_", prefix);
70     path[size - 2] = id;
71     return path;
72 }
73
74
75
76 static void create_winconf(char id, struct WinConf * wcp)
77 {
78     wcp->id = id;
79     wcp->view = 0;
80     wcp->height_type = 0;
81     wcp->width_type = 0;
82 }
83
84
85
86 static void init_winconf_from_file(struct World * world, char id)
87 {
88     char * tmp = "init_winconf_from_file() on window id '_'";
89     char * context = try_malloc(strlen(tmp) + 1, world,
90                                "init_winconf_from_file()");
91     memcpy(context, tmp, strlen(tmp) + 1);
92     context[strlen(tmp) - 2] = id;
93
94     char * path = string_prefixed_id(world, "config/windows/Win_", id);
95     FILE * file = try_fopen(path, "r", world, context);
96     free(path);
97     uint16_t linemax = get_linemax(file, world, context);
98     char line[linemax + 1];
99
100     struct WinConf * winconf = get_winconf_by_id(world, id);
101     try_fgets(line, linemax + 1, file, world, context);
102     winconf->title = try_malloc(strlen(line), world, context);
103     memcpy(winconf->title, line, strlen(line) - 1); /* Eliminate newline char */
104     winconf->title[strlen(line) - 1] = '\0';        /* char at end of string. */
105
106     try_fgets(line, linemax + 1, file, world, context);
107     winconf->draw = line[0];
108
109     try_fgets(line, linemax + 1, file, world, context);
110     winconf->height = atoi(line);
111     if (0 >= winconf->height)
112     {
113         winconf->height_type = 1;
114     }
115     try_fgets(line, linemax + 1, file, world, context);
116     winconf->width = atoi(line);
117     if (0 >= winconf->width)
118     {
119         winconf->width_type = 1;
120     }
121
122     try_fclose(file, world, context);
123     free(context);
124 }
125
126
127
128 static void init_win_from_winconf(struct World * world, char id)
129 {
130     char * tmp = "Trouble in init_win_from_file() with init_win() (win id: _).";
131     char * err = try_malloc(strlen(tmp) + 1, world, "init_win_from_file()");
132     memcpy(err, tmp, strlen(tmp) + 1);
133     err[strlen(tmp) - 3] = id;
134     struct WinConf * winconf = get_winconf_by_id(world, id);
135     void * f = get_drawfunc_by_char(winconf->draw);
136     exit_err(NULL == f, world, err);
137     exit_err(init_win(world->wmeta, &winconf->win, winconf->title,
138                       winconf->height, winconf->width, world, f),
139              world, err);
140     free(err);
141 }
142
143
144
145 extern void save_win_config(struct World * world, char id)
146 {
147     char * f_name = "save_win_config()";
148
149     char * path_tmp = string_prefixed_id(world, "config/windows/Win_tmp_", id);
150     FILE * file = try_fopen(path_tmp, "w", world, f_name);
151
152     struct WinConf * wc = get_winconf_by_id(world, id);
153     uint8_t size = strlen(wc->title) + 2;
154     if (size < 7)
155     {
156         size = 7;
157     }
158     char line[size];
159     sprintf(line, "%s\n", wc->title);
160     try_fwrite(line, sizeof(char), strlen(line), file, world, f_name);
161     sprintf(line, "%c\n", wc->draw);
162     try_fwrite(line, sizeof(char), strlen(line), file, world, f_name);
163     sprintf(line, "%d\n", wc->height);
164     try_fwrite(line, sizeof(char), strlen(line), file, world, f_name);
165     sprintf(line, "%d\n", wc->width);
166     try_fwrite(line, sizeof(char), strlen(line), file, world, f_name);
167
168     char * path = string_prefixed_id(world, "config/windows/Win_", id);
169     try_fclose_unlink_rename(file, path_tmp, path, world, f_name);
170     free(path);
171     free(path_tmp);
172 }
173
174
175
176 static void set_winconf(struct World * world, char id)
177 {
178     struct WinConf * wcp = get_winconf_by_id(world, id);
179     if      (0 == wcp->height_type)
180     {
181         wcp->height = wcp->win->frame.size.y;
182     }
183     else if (1 == wcp->height_type)
184     {
185         wcp->height = wcp->win->frame.size.y - world->wmeta->padframe.size.y
186                       + 1;
187     }
188     if      (0 == wcp->width_type)
189     {
190         wcp->width = wcp->win->frame.size.x;
191     }
192     else if (1 == wcp->width_type)
193     {
194         wcp->width = wcp->win->frame.size.x - world->wmeta->padframe.size.x;
195     }
196 }
197
198
199
200 static struct WinConf * get_winconf_by_id(struct World * world, char id)
201 {
202     uint8_t i = 0;
203     while (1)
204     {
205         if (id == world->winconfs[i].id)
206         {
207             return &world->winconfs[i];
208         }
209         i++;
210     }
211 }
212
213
214
215 static void * get_drawfunc_by_char(char c)
216 {
217     if      ('i' == c)
218     {
219         return draw_info_win;
220     }
221     else if ('k' == c)
222     {
223         return draw_keys_win;
224     }
225     else if ('l' == c)
226     {
227         return draw_log_win;
228     }
229     else if ('m' == c)
230     {
231         return draw_map_win;
232     }
233     return NULL;
234 }
235
236
237
238 static char get_next_winconf_id(struct World * world)
239 {
240     static uint8_t i = 0;
241     char c = world->winconf_ids[i];
242     if (0 == c)
243     {
244         i = 0;
245     }
246     else
247     {
248         i++;
249     }
250     return c;
251 }
252
253
254
255 extern struct WinConf * get_winconf_by_win(struct World * world,
256                                            struct Win * win)
257 {
258     uint8_t i = 0;
259     while (1)
260     {
261         if (win == world->winconfs[i].win)
262         {
263             return &world->winconfs[i];
264         }
265         i++;
266     }
267 }
268
269
270
271 extern struct Win * get_win_by_id(struct World * world, char id)
272 {
273     struct WinConf * wc = get_winconf_by_id(world, id);
274     return wc->win;
275 }
276
277
278
279 extern void init_winconfs(struct World * world)
280 {
281     char * f_name = "init_winconfs()";
282     char * err_o = "Trouble in init_winconfs() with opendir().";
283     char * err_r = "Trouble in init_winconfs() with readdir().";
284     char * err_c = "Trouble in init_winconfs() with closedir().";
285
286     DIR * dp = opendir("config/windows");
287     exit_err(NULL == dp, world, err_o);
288     struct dirent * fn;
289     errno = 0;
290     char * winconf_ids = try_malloc(256, world, f_name);
291     uint8_t i = 0;
292     char id;
293     while (NULL != (fn = readdir(dp)))
294     {
295         if (   5 == strlen(fn->d_name)
296             && fn->d_name == strstr(fn->d_name, "Win_"))
297         {
298             id = fn->d_name[4];
299             winconf_ids[i] = id;
300             i++;
301         }
302     }
303     winconf_ids[i] = '\0';
304     exit_err(errno, world, err_r);
305     exit_err(closedir(dp), world, err_c);
306     world->winconf_ids = try_malloc(strlen(winconf_ids) + 1, world, f_name);
307     memcpy(world->winconf_ids, winconf_ids, strlen(winconf_ids) + 1);
308     free(winconf_ids);
309
310     struct WinConf * winconfs;
311     winconfs = try_malloc(strlen(world->winconf_ids) * sizeof(struct WinConf),
312                                  world, f_name);
313     i = 0;
314     while (0 != (id = get_next_winconf_id(world)))
315     {
316         create_winconf(id, &winconfs[i]);
317         i++;
318     }
319     world->winconfs = winconfs;
320     while (0 != (id = get_next_winconf_id(world)))
321     {
322         init_winconf_from_file(world, id);
323         i++;
324     }
325 }
326
327
328
329 extern void free_winconf(struct World * world, char id)
330 {
331     struct WinConf * wc = get_winconf_by_id(world, id);
332     free(wc->title);
333 }
334
335
336
337 extern void free_winconfs(struct World * world)
338 {
339     char id;
340     while (0 != (id = get_next_winconf_id(world)))
341     {
342         free_winconf(world, id);
343     }
344     free(world->winconf_ids);
345     free(world->winconfs);
346 }
347
348
349
350 extern void init_wins(struct World * world)
351 {
352     char id;
353     while (0 != (id = get_next_winconf_id(world)))
354     {
355         init_win_from_winconf(world, id);
356     }
357 }
358
359
360
361 extern void free_wins(struct World * world)
362 {
363     char id;
364     while (0 != (id = get_next_winconf_id(world)))
365     {
366         free_win(get_win_by_id(world, id));
367     }
368 }
369
370
371
372 extern void sorted_wintoggle(struct World * world)
373 {
374     char * f_name = "sorted_wintoggle()";
375     char * path = "config/windows/toggle_order";
376     FILE * file = try_fopen(path, "r", world, f_name);
377     uint16_t linemax = get_linemax(file, world, f_name);
378     char win_order[linemax + 1];
379     try_fgets(win_order, linemax + 1, file, world, f_name);
380     try_fclose(file, world, f_name);
381     uint8_t i = 0;
382     for (; i < linemax - 1; i++)
383     {
384         if (NULL == strchr(world->winconf_ids, win_order[i]))
385         {
386             continue;
387         }
388         toggle_window(world->wmeta, get_win_by_id(world, win_order[i]));
389     }
390 }
391
392
393
394 extern void reload_win_config(struct World * world)
395 {
396     while (0 != world->wmeta->active)
397     {
398         suspend_win(world->wmeta, world->wmeta->active);
399     }
400     free_wins(world);
401     free_winconfs(world);
402     init_winconfs(world);
403     init_wins(world);
404     sorted_wintoggle(world);
405 }
406
407
408
409 extern void save_win_configs(struct World * world)
410 {
411     char * f_name = "save_win_configs()";
412
413     char id;
414     while (0 != (id = get_next_winconf_id(world)))
415     {
416         save_win_config(world, id);
417     }
418
419     char * path     = "config/windows/toggle_order";
420     char * path_tmp = "config/windows/toggle_order_tmp";
421     FILE * file = try_fopen(path_tmp, "w", world, f_name);
422
423     char line[6];
424     struct Win * w_p = world->wmeta->chain_start;
425     uint8_t i = 0;
426     while (0 != w_p)
427     {
428         struct WinConf * wc = get_winconf_by_win(world, w_p);
429         line[i] = wc->id;
430         w_p = w_p->next;
431         i++;
432     }
433     line[i] = '\n';
434     try_fwrite(line, sizeof(char), strlen(line), file, world, f_name);
435
436     try_fclose_unlink_rename(file, path_tmp, path, world, f_name);
437 }
438
439
440
441 extern uint8_t toggle_window(struct WinMeta * win_meta, struct Win * win)
442 {
443     if (0 != win->frame.curses_win)
444     {
445         return suspend_win(win_meta, win);
446     }
447     else
448     {
449         return append_win(win_meta, win);
450     }
451 }
452
453
454
455 extern void toggle_winconfig(struct World * world, struct Win * win)
456 {
457     struct WinConf * wcp = get_winconf_by_win(world, win);
458     if (0 == wcp->view)
459     {
460         win->draw = draw_winconf;
461         wcp->view = 1;
462     }
463     else
464     {
465         win->draw = get_drawfunc_by_char(wcp->draw);
466         wcp->view = 0;
467     }
468 }
469
470
471
472 extern void toggle_win_height_type(struct World * world, struct Win * win)
473 {
474     struct WinConf * wcp = get_winconf_by_win(world, win);
475     if (0 == wcp->height_type)
476     {
477         wcp->height_type = 1;
478     }
479     else
480     {
481         wcp->height_type = 0;
482     }
483     set_winconf(world, wcp->id);
484 }
485
486
487
488 extern void toggle_win_width_type(struct World * world, struct Win * win)
489 {
490     struct WinConf * wcp = get_winconf_by_win(world, win);
491     if (   0 == wcp->width_type
492         && win->frame.size.x <= world->wmeta->padframe.size.x)
493     {
494         wcp->width_type = 1;
495     }
496     else
497     {
498         wcp->width_type = 0;
499     }
500     set_winconf(world, wcp->id);
501 }
502
503
504
505 extern void scroll_pad(struct WinMeta * win_meta, char dir)
506 {
507     if      ('+' == dir)
508     {
509         reset_pad_offset(win_meta, win_meta->pad_offset + 1);
510     }
511     else if ('-' == dir)
512     {
513         reset_pad_offset(win_meta, win_meta->pad_offset - 1);
514     }
515 }
516
517
518
519 extern uint8_t growshrink_active_window(struct World * world, char change)
520 {
521     if (0 != world->wmeta->active)
522     {
523         struct yx_uint16 size = world->wmeta->active->frame.size;
524         if      (change == '-')
525         {
526             size.y--;
527         }
528         else if (change == '+')
529         {
530             size.y++;
531         }
532         else if (change == '_')
533         {
534             size.x--;
535         }
536         else if (change == '*')
537         {
538             size.x++;
539         }
540         uint8_t x = resize_active_win(world->wmeta, size);
541         struct WinConf * wcp = get_winconf_by_win(world, world->wmeta->active);
542         if (   1 == wcp->width_type
543             && world->wmeta->active->frame.size.x
544                > world->wmeta->padframe.size.x)
545         {
546             wcp->width_type = 0;
547         }
548         set_winconf(world, wcp->id);
549         return x;
550     }
551     return 0;
552 }