Use sigaction() rather than signal().
[cboard.git] / src / menu.c
blob24498d8128d326f00aa03411c0b1ee350ab0fe85
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2018 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
28 #ifdef HAVE_STRINGS_H
29 #include <strings.h>
30 #endif
32 #include "common.h"
33 #include "conf.h"
34 #include "colors.h"
35 #include "strings.h"
36 #include "misc.h"
37 #include "window.h"
38 #include "menu.h"
39 #include "keys.h"
40 #include "rcfile.h"
42 static void
43 set_menu_vars (int c, int rows, int items, int *item, int *top)
45 int selected = *item;
46 int toppos = *top;
48 switch (c)
50 case KEY_HOME:
51 selected = toppos = 0;
52 break;
53 case KEY_END:
54 selected = items;
55 toppos = items - rows + 1;
56 break;
57 case KEY_UP:
58 if (selected - 1 < 0)
60 selected = items;
62 toppos = selected - rows + 1;
64 else
66 selected--;
68 if (toppos && selected <= toppos)
69 toppos = selected;
71 break;
72 case KEY_DOWN:
73 if (selected + 1 > items)
74 selected = toppos = 0;
75 else
77 selected++;
79 if (selected - toppos >= rows)
80 toppos++;
82 break;
83 case KEY_PPAGE:
84 selected -= rows;
86 if (selected < 0)
87 selected = 0;
89 toppos = selected - rows + 1;
91 if (toppos < 0)
92 toppos = 0;
93 break;
94 case KEY_NPAGE:
95 selected += rows;
97 if (selected > items)
98 selected = items;
100 toppos = selected - rows + 1;
102 if (toppos < 0)
103 toppos = 0;
104 break;
105 default:
106 if (selected == MAX_MENU_HEIGHT - 4)
107 toppos = 1;
108 else if (selected <= rows)
109 toppos = 0;
110 else
112 if (selected - toppos > rows)
113 toppos = selected - rows + 1;
115 break;
118 if (toppos < 0)
119 toppos = 0;
121 if (selected >= items)
123 selected = items;
124 toppos = selected - rows + 1;
127 if (toppos < 0)
128 toppos = 0;
130 *item = selected;
131 *top = toppos;
134 static void
135 fix_menu_vals (WIN * win)
137 struct menu_input_s *m = win->data;
138 char buf[COLS - 4];
139 int i = 0;
140 wchar_t *wc;
141 size_t len;
142 int n, nlen = 0, vlen = 0;
144 for (i = 0; m->items[i]; i++);
145 m->total = i;
146 snprintf (buf, sizeof (buf), _("Item %i %s %i Type %ls for help"),
147 m->selected + 1, _("of"), m->total,
148 key_lookup (global_keys, do_global_help));
150 if (!m->cstatic)
152 win->cols = 0;
154 for (i = 0; m->items[i]; i++)
156 wc = str_to_wchar (m->items[i]->name);
157 n = wcslen (wc);
158 free (wc);
159 if (nlen < n)
160 nlen = n;
162 if (m->items[i]->value)
164 wc = str_to_wchar (m->items[i]->value);
165 n = wcslen (wc);
166 if (vlen < n)
167 vlen = n;
169 n = vlen + nlen;
170 free (wc);
172 else
174 char *s = _("empty value");
176 n = (!m->name_only) ? mblen (s, strlen (s)) + nlen : nlen;
179 if (win->cols < n)
180 win->cols = n;
184 if (!m->rstatic)
185 win->rows = i;
187 if (!m->rstatic && win->title)
188 win->rows++;
190 if (!m->cstatic)
191 win->cols += (!m->name_only) ? 5 : 2; // 2 box, 3 separator
193 if (!m->rstatic)
194 win->rows += 3; // 2 box, 1 prompt
196 if (!m->rstatic && win->rows > MAX_MENU_HEIGHT)
197 win->rows = MAX_MENU_HEIGHT;
199 wc = str_to_wchar (buf);
200 len = wcslen (wc);
201 free (wc);
203 if (win->cols < len)
204 win->cols = len + 2; // 2 box
206 if (win->cols > MAX_MENU_WIDTH)
207 win->cols = MAX_MENU_WIDTH;
209 wresize (win->w, win->rows, win->cols);
210 replace_panel (win->p, win->w);
211 move_panel (win->p, (m->ystatic == -1) ? CALCPOSY (win->rows) : m->ystatic,
212 (m->xstatic == -1) ? CALCPOSX (win->cols) : m->xstatic);
213 keypad (win->w, TRUE);
214 wmove (win->w, 0, 0);
215 wclrtobot (win->w);
216 window_draw_title (win->w, win->title, win->cols, CP_INPUT_TITLE,
217 CP_INPUT_BORDER);
218 window_draw_prompt (win->w, win->rows - 2, win->cols, buf, CP_INPUT_PROMPT);
221 void
222 redraw_menu (WIN * win)
224 int i;
225 int y = 0;
226 struct menu_input_s *m = win->data;
228 if (!m->items)
229 return;
231 fix_menu_vals (win);
233 for (i = m->top, y = 2; m->items[i] && y < win->rows - 2; i++, y++)
235 if (i == m->selected)
236 wattron (win->w, CP_MENU_SELECTED);
237 else if (m->items[i]->selected)
238 wattron (win->w, CP_MENU_HIGHLIGHT);
240 if (m->print_func)
242 m->print_line = y;
243 m->item = m->items[i];
244 (*m->print_func) (win);
247 if (i == m->selected)
248 wattroff (win->w, CP_MENU_SELECTED);
249 else if (m->items[i]->selected)
250 wattroff (win->w, CP_MENU_HIGHLIGHT);
254 static int
255 display_menu (WIN * win)
257 struct menu_input_s *m = win->data;
258 int i, n;
259 char *p;
261 cbreak ();
262 noecho ();
263 keypad (win->w, TRUE);
264 nl ();
266 if (m->keys)
268 for (i = 0; m->keys[i]; i++)
270 if (win->c == m->keys[i]->c)
272 (*m->keys[i]->func) (m);
273 m->items = (*m->func) (win);
274 m->search[0] = 0;
275 goto end;
280 switch (win->c)
282 case REFRESH_MENU:
283 m->items = (*m->func) (win);
284 pushkey = 0;
285 break;
286 case -1:
287 pushkey = 0;
288 goto done;
289 case KEY_HOME:
290 case KEY_END:
291 case KEY_UP:
292 case KEY_DOWN:
293 case KEY_NPAGE:
294 case KEY_PPAGE:
295 m->search[0] = 0;
296 break;
297 default:
298 if (!win->c)
299 break;
301 if (strlen (m->search) + 1 > sizeof (m->search) - 1)
302 m->search[0] = 0;
304 p = m->search;
306 while (*p)
307 p++;
309 *p++ = win->c;
310 *p = 0;
311 n = m->selected;
313 if (m->items)
315 for (i = 0; m->items[i]; i++)
317 if (strncasecmp (m->search, m->items[i]->name,
318 strlen (m->search)) == 0)
320 m->selected = i;
321 break;
326 if (n == m->selected)
327 m->search[0] = 0;
330 end:
331 set_menu_vars (win->c, win->rows - 4, m->total - 1, &m->selected, &m->top);
332 redraw_menu (win);
334 if (m->draw_exit_func)
335 (*m->draw_exit_func) (m);
337 update_all (gp);
338 return 1;
340 done:
341 win->data = m->data;
343 if (m->items)
345 for (i = 0; m->items[i]; i++)
347 if (!m->nofree)
348 free (m->items[i]->name);
350 if (!m->nofree && m->items[i]->value)
351 free (m->items[i]->value);
353 free (m->items[i]);
356 free (m->items);
359 if (m->keys)
361 for (i = 0; m->keys[i]; i++)
362 free (m->keys[i]);
364 free (m->keys);
367 free (m);
368 update_all (gp);
369 return 0;
372 static void
373 menu_resize_func (WIN *w)
375 struct menu_input_s *m = w->data;
377 w->rows = m->total >= LINES - 5 ? LINES - 1 : m->total + 5;
378 w->cols = w->cols > COLS - 2 ? COLS - 2 : w->cols;
379 wresize (w->w, w->rows, w->cols);
380 move_panel (w->p, CALCPOSY (w->rows), CALCPOSX (w->cols));
381 wclear (w->w);
382 redraw_menu (w);
385 WIN *
386 construct_menu (int rows, int cols, int y, int x, const char *title,
387 int name_only, menu_items_fn * func,
388 struct menu_key_s ** keys, void *data,
389 menu_print_func * pfunc, window_exit_func * efunc,
390 window_resize_func *rfunc)
392 WIN *win;
393 struct menu_input_s *m;
395 m = Calloc (1, sizeof (struct menu_input_s));
396 win = window_create (title, (rows <= 0) ? 1 : rows, (cols <= 0) ? 1 : cols,
397 (y >= 0) ? y : 0, (x >= 0) ? x : 0, display_menu, m,
398 efunc, rfunc ? rfunc : menu_resize_func);
399 m = win->data;
400 m->ystatic = y;
401 m->xstatic = x;
403 if (rows > 0)
404 m->rstatic = 1;
406 if (cols > 0)
407 m->cstatic = 1;
409 m->print_func = pfunc;
410 m->func = func;
411 m->keys = keys;
412 m->data = data;
413 m->name_only = name_only;
414 wbkgd (win->w, CP_MENU);
415 cbreak ();
416 noecho ();
417 keypad (win->w, TRUE);
418 nl ();
419 m->items = (*m->func) (win);
420 fix_menu_vals (win);
421 (*win->func) (win);
422 return win;
425 void
426 add_menu_key (struct menu_key_s ***dst, wint_t c, menu_key func)
428 int n = 0;
429 struct menu_key_s **keys = *dst;
431 if (keys)
432 for (; keys[n]; n++);
434 keys = Realloc (keys, (n + 2) * sizeof (struct menu_key_s *));
435 keys[n] = Malloc (sizeof (struct menu_key_s));
436 keys[n]->c = c;
437 keys[n++]->func = func;
438 keys[n] = NULL;
439 *dst = keys;