4 #include <stdlib.h> /* for free() */
5 #include <stdint.h> /* for uint16_t */
6 #include <string.h> /* for strlen() */
7 #include <ncurses.h> /* for attri_t, chtype */
8 #include "windows.h" /* for struct Win */
9 #include "misc.h" /* for try_malloc() */
10 #include "keybindings.h" /* for struct KeyBinding, for get_name_to_keycode() */
11 #include "map_objects.h" /* for structs MapObj, get_map_object_def(),
14 #include "map.h" /* for Map struct */
15 #include "main.h" /* for World struct */
16 #include "command_db.h" /* for get_command_longdesc() */
17 #include "wincontrol.h" /* for WinConf struct, get_winconf_by_win() */
21 /* Apply to the winmap of Win "w" the new sizes "new_size_y" and "new_size_x"
22 * to the degree that they extend it. Re-shape the window content accordingly.
24 static void try_resize_winmap(struct World * world, struct Win * w,
25 int new_size_y, int new_size_x);
27 /* In Win "w", write "ch" to coordinate "y"/"x". */
28 static void set_ch_on_yx(struct Win * w, int y, int x, chtype ch);
30 /* Add "text" into window "win". Break text at right window edge. Also break at
33 static void add_text_with_linebreaks(struct World * world, struct Win * win,
36 /* Add "line" into window "w". Apply ncurses attribute "attri" to all
37 * characters drawn. If "fill" is non-zero, fill the entire line until the
38 * right window edge with empty characters ("attri" also applied on these).
40 static void add_line(struct World * world, struct Win * w, char * line,
41 attr_t attri, uint8_t fill);
43 /* Write "text" with add_text_with_linebreaks() as not starting from the top but
44 * from bottom of "win". Draw only what fits in window (avoid scroll hints).
46 static void draw_text_from_bottom(struct World * world, struct Win * win,
49 /* Draw onto "map" in "win" the objects in the chain at "start". */
50 static void draw_map_objects(struct World * world, struct MapObj * start,
51 struct Map * map, struct Win * win);
53 /* Return keybinding list line via "kb_pp", iterate pointer pointed to by it. */
54 static char * get_kb_line_and_iterate(struct World * world,
55 struct KeyBinding ** kb_pp);
57 /* Draw from line "start" on config view for keybindings defined at "kb". */
58 static void draw_kb_view(struct World * world, struct Win * w,
59 struct KeyBiData * kb, uint8_t start);
61 /* Draw into window "w" from line "start" on a "title" followed by an empty
62 * line followed by a list of all keybindings starting at kb_p.
64 static uint16_t draw_titled_keybinding_list(struct World * world, char * title,
65 struct Win * w, uint16_t start,
66 struct KeyBinding * kb_p);
70 static void try_resize_winmap(struct World * world, struct Win * w,
71 int new_size_y, int new_size_x)
73 char * f_name = "try_resize_winmap()";
74 if (w->winmapsize.y >= new_size_y && w->winmapsize.x >= new_size_x)
78 if (w->winmapsize.y > new_size_y)
80 new_size_y = w->winmapsize.y;
82 else if (w->winmapsize.x > new_size_x)
84 new_size_x = w->winmapsize.x;
86 chtype * old_winmap = w->winmap;
87 uint32_t new_size = sizeof(chtype) * new_size_y * new_size_x;
88 w->winmap = try_malloc(new_size, world, f_name);
90 for (y = 0; y < new_size_y; y++)
92 for (x = 0; y < w->winmapsize.y && x < w->winmapsize.x; x++)
94 chtype ch = old_winmap[(y * w->winmapsize.x) + x];
95 w->winmap[(y * new_size_x) + x] = ch;
97 for (; x < new_size_x; x++)
99 w->winmap[(y * new_size_x) + x] = ' ';
103 w->winmapsize.y = new_size_y;
104 w->winmapsize.x = new_size_x;
109 static void set_ch_on_yx(struct Win * w, int y, int x, chtype ch)
111 w->winmap[(y * w->winmapsize.x) + x] = ch;
116 static void add_text_with_linebreaks(struct World * world, struct Win * win,
121 for (y = win->winmapsize.y; ; y++)
123 try_resize_winmap(world, win, y + 1, win->framesize.x);
124 for (x = 0; x < win->framesize.x; x++)
133 set_ch_on_yx(win, y, x, text[z]);
135 if ('\n' == text[z+1])
140 else if (0 == text[z+1])
150 static void add_line(struct World * world, struct Win * w, char * line,
151 attr_t attri, uint8_t fill)
153 uint16_t y = w->winmapsize.y;
154 uint16_t len_line = strlen(line);
156 && w->winmapsize.x < w->framesize.x && w->framesize.x > len_line)
158 try_resize_winmap(world, w, y + 1, w->framesize.x);
162 try_resize_winmap(world, w, y + 1, strlen(line));
165 for (; x < len_line; x++)
167 set_ch_on_yx(w, y, x, line[x] | attri);
171 for (; x < w->framesize.x; x++)
173 set_ch_on_yx(w, y, x, ' ' | attri);
180 static void draw_text_from_bottom(struct World * world, struct Win * win,
183 /* Determine number of lines text would have in a window of win's width,
184 * but infinite height. Treat \n and \0 as control chars for incrementing
185 * y and stopping the loop. Make sure +they* don't count as cell space.
190 for (y = 0; 0 == toggle; y++)
192 for (x = 0; x < win->framesize.x; x++)
199 if ('\n' == text[z+1])
204 else if (0 == text[z+1])
213 /* Depending on what's bigger, determine start point in window or text. */
214 uint16_t start_y = 0;
215 if (y < win->framesize.y)
217 start_y = win->framesize.y - y;
219 else if (y > win->framesize.y)
221 uint16_t offset = y - win->framesize.y;
222 for (y = 0; y < offset; y++)
224 for (x = 0; x < win->framesize.x; x++)
231 if ('\n' == text[z+1])
238 text = text + (sizeof(char) * (z + 1));
241 try_resize_winmap(world, win, start_y, 1);
242 add_text_with_linebreaks(world, win, text);
247 static void draw_map_objects(struct World * world, struct MapObj * start,
248 struct Map * map, struct Win * win)
251 struct MapObjDef * d;
254 for (i = 0; i < 2; i++)
256 for (o = start; o != 0; o = o->next)
258 if (( (0 == i && 0 == o->lifepoints) /* Draw in-animate */
259 || (1 == i && 0 < o->lifepoints))) /* objects first. */
261 d = get_map_object_def(world, o->type);
263 set_ch_on_yx(win, o->pos.y, o->pos.x, c);
271 static char * get_kb_line_and_iterate(struct World * world,
272 struct KeyBinding ** kb_pp)
274 char * f_name = "get_kb_line_and_iterate()";
275 struct KeyBinding * kb_p = * kb_pp;
276 char * keyname = get_name_to_keycode(world, kb_p->key);
277 char * cmd_dsc = get_command_longdsc(world, kb_p->name);
278 uint16_t size = 9 + 1 + strlen(cmd_dsc) + 1;
279 char * line = try_malloc(size, world, f_name);
280 sprintf(line, "%-9s %s", keyname, cmd_dsc);
282 * kb_pp = kb_p->next;
288 static void draw_kb_view(struct World * world, struct Win * w,
289 struct KeyBiData * kb, uint8_t start)
293 add_line(world, w, "(none)", 0, 0);
296 struct KeyBinding * kb_p = kb->kbs;
298 for (y = start; 0 != kb_p; y++)
301 if (y - start == kb->select)
306 attri = attri | A_BLINK;
309 char * kb_line = get_kb_line_and_iterate(world, &kb_p);
310 add_line(world, w, kb_line, attri, 1);
317 static uint16_t draw_titled_keybinding_list(struct World * world, char * title,
318 struct Win * w, uint16_t start,
319 struct KeyBinding * kb_p)
323 for (y = start; (0 == state || 0 != kb_p); y++)
327 add_line(world, w, title, 0, 0);
329 add_line(world, w, " ", 0, 0);
330 state = 1 + (0 == kb_p);
333 char * kb_line = get_kb_line_and_iterate(world, &kb_p);
334 add_line(world, w, kb_line, 0, 0);
339 char * none = "(none)";
340 add_line(world, w, none, 0, 0);
348 extern void draw_win_log(struct Win * win)
350 struct World * world = (struct World *) win->data;
351 draw_text_from_bottom(world, win, world->log);
356 extern void draw_win_map(struct Win * win)
358 struct World * world = (struct World *) win->data;
359 struct Map * map = world->map;
360 char * cells = map->cells;
361 try_resize_winmap(world, win, map->size.y, map->size.x);
364 for (y = 0; y < map->size.y; y++)
366 for (x = 0; x < map->size.x; x++)
368 set_ch_on_yx(win, y, x, cells[z]);
372 draw_map_objects(world, world->map_objs, map, win);
377 extern void draw_win_info(struct Win * win)
379 struct World * world = (struct World *) win->data;
380 char * dsc_turn = "Turn: ";
381 char * dsc_hitpoints = "\nHitpoints: ";
382 char * dsc_score = "\nScore: ";
383 uint16_t maxl = strlen(dsc_turn) + strlen(dsc_hitpoints) + strlen(dsc_score)
384 + 10 + 5 + 10; /* max strlens of numbers to be used */
386 struct MapObj * player = get_player(world);
387 sprintf(text, "%s%d%s%d%s%d",
388 dsc_turn, world->turn,
389 dsc_hitpoints, player->lifepoints,
390 dsc_score, world->score);
391 add_text_with_linebreaks(world, win, text);
396 extern void draw_win_inventory(struct Win * win)
398 struct World * world = (struct World *) win->data;
399 struct MapObj * player = get_player(world);
400 if (NULL == player->owns)
402 add_line(world, win, "(none)", 0, 0);
405 win->center.y = world->inventory_select;
406 struct MapObj * owned = player->owns;
408 for (y = 0; NULL != owned; y++)
411 if (y == world->inventory_select)
415 struct MapObjDef * mod = get_map_object_def(world, owned->type);
416 add_line(world, win, mod->name, attri, 0);
423 extern void draw_win_available_keybindings(struct Win * win)
425 struct World * world = (struct World *) win->data;
426 char * title = "Active window's keybindings:";
427 struct KeyBinding * kb_p;
428 struct WinConf * wc = get_winconf_by_win(world, world->wmeta->active);
433 else if (1 == wc->view)
435 kb_p = world->kb_wingeom.kbs;
437 else if (2 == wc->view)
439 kb_p = world->kb_winkeys.kbs;
441 uint16_t offset = draw_titled_keybinding_list(world, title, win, 0, kb_p);
442 add_line(world, win, " ", 0, 0);
443 draw_titled_keybinding_list(world, "Global keybindings", win, offset + 1,
444 world->kb_global.kbs);
449 extern void draw_win_keybindings_global(struct Win * win)
451 struct World * world = (struct World *) win->data;
452 win->center.y = world->kb_global.select;
453 draw_kb_view(world, win, &world->kb_global, 0);
458 extern void draw_win_keybindings_winconf_geometry(struct Win * win)
460 struct World * world = (struct World *) win->data;
461 win->center.y = world->kb_wingeom.select;
462 draw_kb_view(world, win, &world->kb_wingeom, 0);
467 extern void draw_win_keybindings_winconf_keybindings(struct Win * win)
469 struct World * world = (struct World *) win->data;
470 win->center.y = world->kb_winkeys.select;
471 draw_kb_view(world, win, &world->kb_winkeys, 0);
476 extern void draw_winconf_keybindings(struct Win * win)
478 struct World * world = (struct World *) win->data;
479 struct WinConf * wc = get_winconf_by_win(world, win);
480 char * title = "Window's keybindings:";
481 add_line(world, win, title, 0, 0);
482 add_line(world, win, " ", 0, 0);
483 draw_kb_view(world, win, &wc->kb, 2);
484 win->center.y = wc->kb.select + 2;
489 extern void draw_winconf_geometry(struct Win * win)
491 struct World * world = (struct World *) win->data;
492 struct WinConf * wcp = get_winconf_by_win(world, win);
493 char * title = "Window's geometry:\n";
494 char * h_d = "\nHeight to save: ";
495 char * h_pos = " (width in cells)";
496 char * h_neg = " (negative diff: cells to maximum width)";
497 char * w_d = "\n\nWidth to save: ";
498 char * w_pos = " (height in cells)";
499 char * w_neg = " (negative diff: cells to maximum height)";
502 if (1 == wcp->height_type)
506 if (1 == wcp->width_type)
510 uint16_t maxl = strlen(title)
511 + strlen(h_t) + strlen(h_d) + 6
512 + strlen(w_t) + strlen(w_d) + 6 + 1;
514 sprintf(text, "%s%s%d%s%s%d%s", title, h_d, wcp->height, h_t,
515 w_d, wcp->width, w_t);
516 add_text_with_linebreaks(world, win, text);