Build fix.
[cboard.git] / src / menu.c
blob293951a9a888ebb41f6e33a52cb027aea8a73aed
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2013 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"
40 static void set_menu_vars(int c, int rows, int items, int *item, int *top)
42 int selected = *item;
43 int toppos = *top;
45 switch (c) {
46 case KEY_HOME:
47 selected = toppos = 0;
48 break;
49 case KEY_END:
50 selected = items;
51 toppos = items - rows + 1;
52 break;
53 case KEY_UP:
54 if (selected - 1 < 0) {
55 selected = items;
57 toppos = selected - rows + 1;
59 else {
60 selected--;
62 if (toppos && selected <= toppos)
63 toppos = selected;
65 break;
66 case KEY_DOWN:
67 if (selected + 1 > items )
68 selected = toppos = 0;
69 else {
70 selected++;
72 if (selected - toppos >= rows)
73 toppos++;
75 break;
76 case KEY_PPAGE:
77 selected -= rows;
79 if (selected < 0)
80 selected = 0;
82 toppos = selected - rows + 1;
84 if (toppos < 0)
85 toppos = 0;
86 break;
87 case KEY_NPAGE:
88 selected += rows;
90 if (selected > items)
91 selected = items;
93 toppos = selected - rows + 1;
95 if (toppos < 0)
96 toppos = 0;
97 break;
98 default:
99 if (selected == MAX_MENU_HEIGHT - 4)
100 toppos = 1;
101 else if (selected <= rows)
102 toppos = 0;
103 else {
104 if (selected - toppos > rows)
105 toppos = selected - rows + 1;
107 break;
110 if (toppos < 0)
111 toppos = 0;
113 if (selected >= items) {
114 selected = items;
115 toppos = selected - rows + 1;
118 if (toppos < 0)
119 toppos = 0;
121 *item = selected;
122 *top = toppos;
125 static void fix_menu_vals(WIN *win)
127 struct menu_input_s *m = win->data;
128 char buf[COLS - 4];
129 int i = 0;
130 #ifdef HAVE_WRESIZE
131 int n, nlen = 0, vlen = 0;
132 #endif
134 for (i = 0; m->items[i]; i++);
135 m->total = i;
136 snprintf(buf, sizeof(buf), "Item %i %s %i %s", m->selected + 1,
137 N_OF_N_STR, m->total, HELP_PROMPT);
139 #ifdef HAVE_WRESIZE
140 if (!m->cstatic) {
141 win->cols = 0;
143 for (i = 0; m->items[i]; i++) {
144 n = strlen(m->items[i]->name);
146 if (nlen < n)
147 nlen = n;
149 if (m->items[i]->value) {
150 n = strlen(m->items[i]->value);
152 if (vlen < n)
153 vlen = n;
155 n = vlen + nlen;
157 else
158 n = (!m->name_only) ? strlen(UNKNOWN) + nlen : nlen;
160 if (win->cols < n)
161 win->cols = n;
165 if (!m->rstatic)
166 win->rows = i;
168 if (!m->rstatic && win->title)
169 win->rows++;
171 if (!m->cstatic)
172 win->cols += (!m->name_only) ? 5 : 2; // 2 box, 3 separator
174 if (!m->rstatic)
175 win->rows += 3; // 2 box, 1 prompt
177 if (!m->rstatic && win->rows > MAX_MENU_HEIGHT)
178 win->rows = MAX_MENU_HEIGHT;
180 if (win->cols < strlen(buf))
181 win->cols = strlen(buf) + 2; // 2 box
183 if (win->cols > MAX_MENU_WIDTH)
184 win->cols = MAX_MENU_WIDTH;
186 wresize(win->w, win->rows, win->cols);
187 replace_panel(win->p, win->w);
188 #endif
189 move_panel(win->p, (m->ystatic == -1) ? CALCPOSY(win->rows) : m->ystatic,
190 (m->xstatic == -1) ? CALCPOSX(win->cols) : m->xstatic);
191 keypad(win->w, TRUE);
192 wmove(win->w, 0, 0);
193 wclrtobot(win->w);
194 window_draw_title(win->w, win->title, win->cols, CP_INPUT_TITLE,
195 CP_INPUT_BORDER);
196 window_draw_prompt(win->w, win->rows - 2, win->cols, buf, CP_INPUT_PROMPT);
199 static void draw_menu(WIN *win)
201 int i;
202 int y = 0;
203 struct menu_input_s *m = win->data;
205 if (!m->items)
206 return;
208 for (i = m->top, y = 2; m->items[i] && y < win->rows - 2; i++, y++) {
209 if (i == m->selected)
210 wattron(win->w, CP_MENU_SELECTED);
211 else if (m->items[i]->selected)
212 wattron(win->w, CP_MENU_HIGHLIGHT);
214 if (m->print_func) {
215 m->print_line = y;
216 m->item = m->items[i];
217 (*m->print_func)(win);
220 if (i == m->selected)
221 wattroff(win->w, CP_MENU_SELECTED);
222 else if (m->items[i]->selected)
223 wattroff(win->w, CP_MENU_HIGHLIGHT);
227 static int display_menu(WIN *win)
229 struct menu_input_s *m = win->data;
230 int i, n;
231 char *p;
233 cbreak();
234 noecho();
235 keypad(win->w, TRUE);
236 nl();
238 if (m->keys) {
239 for (i = 0; m->keys[i]; i++) {
240 if (win->c == m->keys[i]->c) {
241 (*m->keys[i]->func)(m);
242 m->items = (*m->func)(win);
243 m->search[0] = 0;
244 goto end;
249 switch (win->c) {
250 case REFRESH_MENU:
251 m->items = (*m->func)(win);
252 pushkey = 0;
253 break;
254 case -1:
255 pushkey = 0;
256 goto done;
257 case KEY_HOME:
258 case KEY_END:
259 case KEY_UP:
260 case KEY_DOWN:
261 case KEY_NPAGE:
262 case KEY_PPAGE:
263 m->search[0] = 0;
264 break;
265 default:
266 if (!win->c)
267 break;
269 if (strlen(m->search) + 1 > sizeof(m->search) - 1)
270 m->search[0] = 0;
272 p = m->search;
274 while (*p)
275 p++;
277 *p++ = win->c;
278 *p = 0;
279 n = m->selected;
281 if (m->items) {
282 for (i = 0; m->items[i]; i++) {
283 if (strncasecmp(m->search, m->items[i]->name,
284 strlen(m->search)) == 0) {
285 m->selected = i;
286 break;
291 if (n == m->selected)
292 m->search[0] = 0;
295 end:
296 set_menu_vars(win->c, win->rows - 4, m->total - 1, &m->selected, &m->top);
297 fix_menu_vals(win);
298 draw_menu(win);
300 if (m->draw_exit_func)
301 (*m->draw_exit_func)(m);
303 update_all(gp);
304 return 1;
306 done:
307 win->data = m->data;
309 if (m->items) {
310 for (i = 0; m->items[i]; i++) {
311 if (!m->nofree)
312 free(m->items[i]->name);
314 if (!m->nofree && m->items[i]->value)
315 free(m->items[i]->value);
317 free(m->items[i]);
320 free(m->items);
323 if (m->keys) {
324 for (i = 0; m->keys[i]; i++)
325 free(m->keys[i]);
327 free(m->keys);
330 free(m);
331 update_all(gp);
332 return 0;
335 WIN *construct_menu(int rows, int cols, int y, int x, const char *title,
336 int name_only, menu_items_fn *func,
337 struct menu_key_s **keys, void *data,
338 menu_print_func *pfunc, window_exit_func *efunc)
340 WIN *win;
341 struct menu_input_s *m;
343 #ifndef HAVE_WRESIZE
344 if (rows <= 0)
345 rows = MAX_MENU_HEIGHT;
347 if (cols <= 0)
348 cols = MAX_MENU_WIDTH;
349 #endif
351 m = Calloc(1, sizeof(struct menu_input_s));
352 win = window_create(title, (rows <= 0) ? 1 : rows, (cols <= 0) ? 1 : cols,
353 (y >= 0) ? y : 0, (x >= 0) ? x : 0, display_menu, m, efunc);
354 m = win->data;
355 m->ystatic = y;
356 m->xstatic = x;
358 #ifndef HAVE_WRESIZE
359 m->rstatic = 1;
360 m->cstatic = 1;
361 #else
362 if (rows > 0)
363 m->rstatic = 1;
365 if (cols > 0)
366 m->cstatic = 1;
367 #endif
369 m->print_func = pfunc;
370 m->func = func;
371 m->keys = keys;
372 m->data = data;
373 m->name_only = name_only;
374 wbkgd(win->w, CP_MENU);
375 cbreak();
376 noecho();
377 keypad(win->w, TRUE);
378 nl();
379 m->items = (*m->func)(win);
380 fix_menu_vals(win);
381 (*win->func)(win);
382 return win;
385 void add_menu_key(struct menu_key_s ***dst, int c, menu_key func)
387 int n = 0;
388 struct menu_key_s **keys = *dst;
390 if (keys)
391 for (; keys[n]; n++);
393 keys = Realloc(keys, (n + 2) * sizeof(struct menu_key_s *));
394 keys[n] = Malloc(sizeof(struct menu_key_s));
395 keys[n]->c = c;
396 keys[n++]->func = func;
397 keys[n] = NULL;
398 *dst = keys;