home · contact · privacy
Window configuration can now be saved; and edited in a special window config view...
[plomrogue] / src / draw_wins.c
1 /* draw_wins.c */
2
3 #include "draw_wins.h"
4 #include <stdlib.h>      /* for malloc(), free() */
5 #include <stdint.h>      /* for uint16_t */
6 #include <string.h>      /* for strlen() */
7 #include <ncurses.h>     /* for mvwaddch() */
8 #include "windows.h"     /* for structs Win, Frame, for draw_scroll_hint() */
9 #include "misc.h"        /* for center_offset() */
10 #include "keybindings.h" /* for struct KeyBinding, for get_keyname() */
11 #include "map_objects.h" /* for structs MapObj, Player */
12 #include "map.h"         /* for Map struct */
13 #include "main.h"        /* for World struct */
14 #include "rexit.h"       /* for err_exit() */
15 #include "command_db.h"  /* for get_command_longdesc() */
16 #include "wincontrol.h"  /* for WinConf struct, get_winconf_by_win() */
17
18
19
20 /* Write "text" into window "win" as far as possible. Start on row "start_y". */
21 static void draw_with_linebreaks(struct Win * win, char * text,
22                                  uint16_t start_y);
23
24 /* Write "text" not starting from the top but from the bottom of "win". */
25 static void draw_text_from_bottom(struct Win * win, char * text);
26
27 /* Draw onto "map" in "win" the objects in the chain at "start". */
28 static void draw_map_objects(struct World * world, struct MapObj * start,
29                              struct Map * map, struct Win * win);
30
31
32
33 static void draw_with_linebreaks(struct Win * win, char * text,
34                                  uint16_t start_y)
35 {
36     uint16_t x, y;
37     char toggle;
38     char fin = 0;
39     int16_t z = -1;
40     for (y = start_y; y < win->frame.size.y; y++)
41     {
42         if (0 == fin)
43         {
44             toggle = 0;
45         }
46         for (x = 0; x < win->frame.size.x; x++)
47         {
48             if (0 == toggle)
49             {
50                 z++;
51                 if ('\n' == text[z])
52                 {
53                     toggle = 1;
54                     continue;
55                 }
56                 else
57                 {
58                     mvwaddch(win->frame.curses_win, y, x, text[z]);
59                 }
60                 if ('\n' == text[z+1])
61                 {
62                     z++;
63                     toggle = 1;
64                 }
65                 else if (0 == text[z+1])
66                 {
67                     toggle = 1;
68                     fin = 1;
69                 }
70             }
71         }
72     }
73 }
74
75
76
77 static void draw_text_from_bottom (struct Win * win, char * text)
78 {
79     /* Determine number of lines text would have in a window of win's width,
80      * but infinite height. Treat \n and \0 as control chars for incrementing
81      * y and stopping the loop. Make sure +they* don't count as cell space.
82      */
83     char toggle = 0;
84     uint16_t x, y, offset;
85     int16_t z = -1;
86     for (y = 0; 0 == toggle; y++)
87     {
88         for (x = 0; x < win->frame.size.x; x++)
89         {
90             z++;
91             if ('\n' == text[z])
92             {
93                 break;
94             }
95             if ('\n' == text[z+1])
96             {
97                 z++;
98                 break;
99             }
100             else if (0 == text[z+1])
101             {
102                 toggle = 1;
103                 break;
104             }
105         }
106     }
107     z = -1;
108
109     /* Depending on what's bigger, determine start point in window or text. */
110     uint16_t start_y = 0;
111     if (y < win->frame.size.y)
112     {
113         start_y = win->frame.size.y - y;
114     }
115     else if (y > win->frame.size.y)
116     {
117         offset = y - win->frame.size.y;
118         for (y = 0; y < offset; y++)
119         {
120             for (x = 0; x < win->frame.size.x; x++)
121             {
122                 z++;
123                 if ('\n' == text[z])
124                 {
125                     break;
126                 }
127                 if ('\n' == text[z+1])
128                 {
129                     z++;
130                     break;
131                 }
132             }
133         }
134         text = text + (sizeof(char) * (z + 1));
135     }
136
137     draw_with_linebreaks(win, text, start_y);
138 }
139
140
141
142 static void draw_map_objects(struct World * world, struct MapObj * start,
143                              struct Map * map, struct Win * win)
144 {
145     struct MapObj * o;
146     struct MapObjDef * d;
147     char c;
148     for (o = start; o != 0; o = o->next)
149     {
150         if (   o->pos.y >= map->offset.y
151             && o->pos.y < map->offset.y + win->frame.size.y
152             && o->pos.x >= map->offset.x
153             && o->pos.x < map->offset.x + win->frame.size.x)
154         {
155             d = get_map_obj_def (world, o->type);
156             c = d->mapchar;
157             mvwaddch(win->frame.curses_win,
158                      o->pos.y - map->offset.y, o->pos.x - map->offset.x, c);
159         }
160     }
161 }
162
163
164
165 extern void draw_log_win(struct Win * win)
166 {
167     struct World * world = (struct World *) win->data;
168     draw_text_from_bottom(win, world->log);
169 }
170
171
172
173 extern void draw_map_win(struct Win * win)
174 {
175     struct World * world = (struct World *) win->data;
176     struct Map * map = world->map;
177     struct Player * player = world->player;
178     char * cells = map->cells;
179     uint16_t width_map_av  = map->size.x  - map->offset.x;
180     uint16_t height_map_av = map->size.y - map->offset.y;
181     uint16_t x, y, z;
182     for (y = 0; y < win->frame.size.y; y++)
183     {
184         z = map->offset.x + (map->offset.y + y) * (map->size.x);
185         for (x = 0; x < win->frame.size.x; x++)
186         {
187             if (y < height_map_av && x < width_map_av)
188             {
189                 mvwaddch(win->frame.curses_win, y, x, cells[z]);
190                 z++;
191             }
192         }
193     }
194     draw_map_objects (world, (struct MapObj *) world->item, map, win);
195     draw_map_objects (world, (struct MapObj *) world->monster, map, win);
196     if (   player->pos.y >= map->offset.y
197         && player->pos.y < map->offset.y + win->frame.size.y
198         && player->pos.x >= map->offset.x
199         && player->pos.x < map->offset.x + win->frame.size.x)
200     {
201         mvwaddch(win->frame.curses_win,
202                  player->pos.y - map->offset.y, player->pos.x - map->offset.x,
203                  '@');
204     }
205 }
206
207
208
209 extern void draw_info_win(struct Win * win)
210 {
211     struct World * world = (struct World *) win->data;
212     char * dsc_turn      = "Turn: ";
213     char * dsc_hitpoints = "\nHitpoints: ";
214     char * dsc_score     = "\nScore: ";
215     uint16_t maxl = strlen(dsc_turn) + strlen(dsc_hitpoints) + strlen(dsc_score)
216                     + 10 + 5 + 10;       /* max strlens of numbers to be used */
217     char * text = malloc(maxl + 1);
218     sprintf(text, "%s%d%s%d%s%d",
219             dsc_turn, world->turn,
220             dsc_hitpoints, world->player->hitpoints,
221             dsc_score, world->score);
222     draw_with_linebreaks(win, text, 0);
223     free(text);
224 }
225
226
227
228 extern void draw_keys_win(struct Win * win)
229 {
230     struct World * world = (struct World *) win->data;
231     uint16_t offset, y, x;
232     offset = center_offset(world->keyswindata->select, world->keyswindata->max,
233                            win->frame.size.y - 1);
234     uint8_t keydescwidth = 9 + 1; /* max length assured by get_keyname() + \0 */
235     char * keydesc = malloc(keydescwidth), * keyname;
236     char * err_hint = "Trouble with draw_scroll_hint() in draw_keys_win().";
237     attr_t attri;
238     char * cmd_dsc;
239     for (y = 0; y <= world->keyswindata->max && y < win->frame.size.y; y++)
240     {
241         if (0 == y && offset > 0)
242         {
243             exit_err(draw_scroll_hint(&win->frame, y, offset + 1, '^'),
244                      world, err_hint);
245             continue;
246         }
247         else if (win->frame.size.y == y + 1
248                  && 0 < world->keyswindata->max
249                         - (win->frame.size.y + offset - 1))
250         {
251             exit_err(draw_scroll_hint(&win->frame, y,
252                                       world->keyswindata->max
253                                        - (offset + win->frame.size.y) + 2, 'v'),
254                      world, err_hint);
255             continue;
256         }
257         attri = 0;
258         if (y == world->keyswindata->select - offset)
259         {
260             attri = A_REVERSE;
261             if (1 == world->keyswindata->edit)
262             {
263                 attri = attri | A_BLINK;
264             }
265         }
266         keyname = get_keyname(world->keybindings[y + offset].key);
267         snprintf(keydesc, keydescwidth, "%-9s", keyname);
268         free(keyname);
269         cmd_dsc = get_command_longdsc(world,
270                                       world->keybindings[y + offset].name);
271         for (x = 0; x < win->frame.size.x; x++)
272         {
273             if (x < strlen(keydesc))
274             {
275                 mvwaddch(win->frame.curses_win, y, x, keydesc[x] | attri);
276             }
277             else if (   strlen(keydesc) < x
278                      && x < strlen(cmd_dsc) + strlen(keydesc) + 1)
279             {
280                 mvwaddch(win->frame.curses_win, y, x,
281                          cmd_dsc[x - strlen(keydesc) - 1] | attri);
282             }
283             else
284             {
285                 mvwaddch(win->frame.curses_win, y, x, ' ' | attri);
286             }
287         }
288     }
289     free(keydesc);
290 }
291
292
293
294 extern void draw_winconf(struct Win * win)
295 {
296     struct World * world = (struct World *) win->data;
297     struct WinConf * wcp = get_winconf_by_win(world, win);
298     char * title = "Window configuration:\n";
299     char * h_t_d = "\nWill save height as: ";
300     char * h_pos = "height in positive cells";
301     char * h_neg = "negative diff to maximum height";
302     char * h_d   = "\nHeight to be saved: ";
303     char * w_t_d = "\n\nWill save width as: ";
304     char * w_pos = "width in positive cells";
305     char * w_neg = "negative diff to maximum width";
306     char * w_d   = "\nWidth to be saved: ";
307     char * h_t = h_pos;
308     char * w_t = w_pos;
309     if      (1 == wcp->height_type)
310     {
311         h_t = h_neg;
312     }
313     if     (1 == wcp->width_type)
314     {
315         w_t = w_neg;
316     }
317     uint16_t maxl = strlen(title)
318                     + strlen(h_t_d) + strlen(h_t) + strlen(h_d) + 6
319                     + strlen(w_t_d) + strlen(w_t) + strlen(w_d) + 6 + 1;
320     char * text = malloc(maxl + 1);
321     sprintf(text, "%s%s%s%s%d%s%s%s%d", title, h_t_d, h_t, h_d, wcp->height,
322                                                w_t_d, w_t, w_d, wcp->width);
323     draw_with_linebreaks(win, text, 0);
324     free(text);
325 }