1 /*
2 cursesmenudisplay.c
3
4 Copyright (C) 2010-2019 Amf
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <string.h>
24
25 #ifdef CHROMA_CURSES_HEADER
26 #include CHROMA_CURSES_HEADER
27 #else
28 #ifdef __WIN32__
29 #include <curses.h>
30 #else
31 #include <ncurses.h>
32 #endif
33 #endif
34
35 #include "chroma.h"
36 #include "menu.h"
37 #include "actions.h"
38 #include "level.h"
39 #include "display.h"
40 #include "util.h"
41
42 #define MAX_WIDTH 65
43
44 extern int display_size_x, display_size_y;
45 extern int actions[KEY_MAX];
46
47 extern short colourpair_menu;
48 extern short colourpair_menugrey;
49 extern short colourpair_red;
50 extern short colourpair_green;
51 extern short colourpair_yellow;
52 extern short colourpair_blue;
53 extern short colourpair_cyan;
54 extern short colourpair_magenta;
55 extern short colourpair_cyan;
56 extern short colourpair_white;
57
58 int menu_offset;
59 int menu_width;
60 int menu_height_notes;
61 int menu_height_entries;
62 int menu_y_min;
63 int menu_y_max;
64 int menu_y_logo_top;
65 int menu_y_logo_bottom;
66 int menu_scroll_y_min;
67 int menu_scroll_y_max;
68 int menu_scroll_top;
69 int menu_scroll_bottom;
70
menu_entryheight(struct menuentry * pentry)71 int menu_entryheight(struct menuentry *pentry)
72 {
73 if(pentry->flags & MENU_INVISIBLE)
74 return 0;
75 if(pentry->flags & MENU_DOUBLE)
76 return 2;
77 return 1;
78 }
79
menu_displayentry(struct menu * pmenu,struct menuentry * pentry,int y,int selected)80 void menu_displayentry(struct menu *pmenu, struct menuentry *pentry, int y, int selected)
81 {
82 char buffer[MAX_WIDTH + 1];
83 int x, i;
84
85 if(menu_width < 1)
86 return;
87
88 if(pentry->flags & MENU_INVISIBLE)
89 return;
90
91 if(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_TEXT))
92 selected = 0;
93
94 /* Plot first line, if visible */
95 if((y >= menu_y_min && y < menu_y_max) || (pentry->flags & MENU_NOTE))
96 {
97 /* Plot key press */
98 attron(COLOR_PAIR(colourpair_white));
99 if(pentry->key != 0 && pentry->key != MENU_KEY_ANY)
100 {
101 mvprintw(y, menu_offset - 4, "[ ] ");
102 attron(A_BOLD);
103 mvprintw(y, menu_offset - 3, "%c", pentry->key);
104 attroff(A_BOLD);
105 }
106 else
107 mvprintw(y, menu_offset - 4, " ");
108 attroff(COLOR_PAIR(colourpair_white));
109
110 /* Determine colour */
111 if(pentry->flags & (MENU_GREY | MENU_SPACE))
112 attron(COLOR_PAIR(colourpair_menugrey));
113 else if(pentry->flags & MENU_NOTE)
114 {
115 if(pmenu->logo == 0)
116 attron(COLOR_PAIR(colourpair_menugrey));
117 }
118 else if(pentry->flags & MENU_TEXT)
119 attron(COLOR_PAIR(colourpair_white));
120 else
121 attron(COLOR_PAIR(colourpair_menu));
122 if(selected)
123 attron(A_REVERSE);
124
125 /* Blank line */
126 move(y, menu_offset);
127 for(i = 0; i < menu_width; i ++)
128 addch(' ');
129
130 /* Plot right hand side text */
131 if(pentry->text2 != NULL)
132 {
133 utf8strncpy(buffer, pentry->text2, menu_width - 2);
134 x = menu_offset + menu_width - 1 - utf8strlen(buffer);
135 mvprintw(y, x, "%s", buffer);
136 }
137
138 /* Plot main text */
139 if(pentry->text != NULL)
140 {
141 utf8strncpy(buffer, pentry->text, menu_width - 2);
142
143 x = menu_offset + 1;
144 if(pentry->flags & MENU_RIGHT)
145 x = menu_offset + menu_width - utf8strlen(buffer);
146 if(pentry->flags & MENU_CENTRE)
147 x = menu_offset + ((menu_width - utf8strlen(buffer))/2);
148
149 if(pentry->flags & MENU_BOLD)
150 attron(A_BOLD);
151 mvprintw(y, x, "%s", buffer);
152 if(pentry->flags & MENU_BOLD)
153 attroff(A_BOLD);
154 }
155
156 if(selected)
157 attroff(A_REVERSE);
158 if(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE))
159 attroff(COLOR_PAIR(colourpair_menugrey));
160 else if(pentry->flags & MENU_TEXT)
161 attroff(COLOR_PAIR(colourpair_white));
162 else
163 attroff(COLOR_PAIR(colourpair_menu));
164 }
165
166 if(!(pentry->flags & MENU_DOUBLE))
167 return;
168
169 y ++;
170
171 /* Plot second line, if visible */
172 if((y >= menu_y_min && y < menu_y_max) || (pentry->flags & MENU_NOTE))
173 {
174 /* Blank key press area */
175 attron(COLOR_PAIR(colourpair_white));
176 mvprintw(y, menu_offset - 4, " ");
177 attroff(COLOR_PAIR(colourpair_white));
178
179 /* Determine colour */
180 if(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE))
181 attron(COLOR_PAIR(colourpair_menugrey));
182 else
183 attron(COLOR_PAIR(colourpair_menu));
184 if(selected)
185 attron(A_REVERSE);
186
187 /* Blank line */
188 move(y, menu_offset);
189 for(i = 0; i < menu_width; i ++)
190 addch(' ');
191
192 /* Plot right hand side text */
193 if(pentry->text4 != NULL)
194 {
195 utf8strncpy(buffer, pentry->text4, menu_width - 2);
196
197 x = menu_offset + menu_width - 1 - utf8strlen(buffer);
198 if(pentry->flags & MENU_EDITING)
199 attron(COLOR_PAIR(colourpair_white));
200 mvprintw(y, x, "%s", buffer);
201 if(pentry->flags & MENU_EDITING)
202 attroff(COLOR_PAIR(colourpair_white));
203 }
204
205 /* Plot left hand side text */
206 if(pentry->text3 != NULL)
207 {
208 utf8strncpy(buffer, pentry->text3, menu_width - 2);
209
210 x = menu_offset + 1;
211 mvprintw(y, x, "%s", buffer);
212 }
213
214 if(selected)
215 attroff(A_REVERSE);
216 if(pentry->flags & (MENU_GREY | MENU_SPACE))
217 attroff(COLOR_PAIR(colourpair_menugrey));
218 else if(pentry->flags & MENU_NOTE)
219 {
220 if(pmenu->logo == 0)
221 attroff(COLOR_PAIR(colourpair_menugrey));
222 }
223 else
224 attroff(COLOR_PAIR(colourpair_menu));
225 }
226 }
227
menu_display(struct menu * pmenu,int redraw)228 void menu_display(struct menu *pmenu, int redraw)
229 {
230 struct menuentry *pentry;
231 int x, y, selected;
232 char title[] = "chroma";
233 char buffer[256];
234 int i;
235 int state;
236 int y_editing;
237 short cp;
238 int j;
239
240 /* 012345678901234567890123456789012345678901 */
241 char logo[] = " 8 "
242 " 8 "
243 ".oPYo. 8oPYo. oPYo. .oPYo. ooYoYo. .oPYo. "
244 "8 ' 8 8 8 `' 8 8 8' 8 8 .oooo8 "
245 "8 . 8 8 8 8 8 8 8 8 8 8 "
246 "`YooP' 8 8 8 `YooP' 8 8 8 `YooP8 ";
247
248 #define LOGO_HEIGHT 7
249
250 /* Calculate various widths */
251 menu_width = display_size_x - 2;
252 if(menu_width > MAX_WIDTH)
253 menu_width = MAX_WIDTH;
254
255 menu_offset = (display_size_x - menu_width) / 2;
256 if(menu_offset < 0)
257 menu_offset = 0;
258
259 menu_width -= 5;
260 menu_offset += 4;
261
262 /* Calculate various heights */
263 menu_height_notes = 0;
264 menu_height_entries = 0;
265
266 pentry = pmenu->entry_first;
267 while(pentry != NULL)
268 {
269 if(pentry->flags & MENU_NOTE)
270 menu_height_notes += menu_entryheight(pentry);
271 else
272 menu_height_entries += menu_entryheight(pentry);
273 pentry = pentry->next;
274 }
275
276 /* Add an extra line to pad the notes out, if there are any */
277 if(menu_height_notes != 0)
278 menu_height_notes += 1;
279
280 if(pmenu->logo)
281 {
282 menu_y_logo_top = (display_size_y - menu_height_entries - LOGO_HEIGHT) / 2;
283 if(menu_y_logo_top < 0)
284 menu_y_logo_top = 0;
285 menu_y_logo_bottom = menu_y_logo_top + LOGO_HEIGHT;
286 menu_y_min = display_size_y - menu_height_entries - 1;
287 if(menu_y_min < menu_y_logo_bottom)
288 menu_y_min = menu_y_logo_bottom;
289 menu_y_max = display_size_y - 1;
290 }
291 else
292 {
293 menu_y_min = 4;
294 menu_y_max = display_size_y - menu_height_notes - 1;
295 if(pmenu->title != NULL)
296 menu_y_min += 2;
297 }
298
299 /* If a full redraw, clear the screen and plot the title */
300 if(redraw == MENUREDRAW_ALL)
301 {
302 clear();
303 curs_set(0);
304
305 if(pmenu->logo)
306 {
307 x = (display_size_x - 42) / 2;
308 y = menu_y_logo_top;
309 cp = colourpair_red;
310
311 move(y, x);
312
313 for(i = 0; i < strlen(logo); i ++)
314 {
315 addch(logo[i] | A_BOLD | COLOR_PAIR(cp));
316 switch(i % 42)
317 {
318 case 6:
319 cp = colourpair_yellow;
320 break;
321 case 13:
322 cp = colourpair_green;
323 break;
324 case 18:
325 cp = colourpair_cyan;
326 break;
327 case 25:
328 cp = colourpair_blue;
329 break;
330 case 33:
331 cp = colourpair_magenta;
332 break;
333 case 41:
334 y ++;
335 move(y, x);
336 cp = colourpair_red;
337 break;
338 }
339 }
340
341 y ++;
342
343 }
344 else
345 {
346 /* Display game title */
347 x = (display_size_x / 2) - strlen(title);
348
349 attron(A_BOLD);
350 for(i = 0; i < strlen(title); i ++)
351 {
352 if(i == 0) attron(COLOR_PAIR(colourpair_red));
353 if(i == 1) attron(COLOR_PAIR(colourpair_yellow));
354 if(i == 2) attron(COLOR_PAIR(colourpair_green));
355 if(i == 3) attron(COLOR_PAIR(colourpair_cyan));
356 if(i == 4) attron(COLOR_PAIR(colourpair_blue));
357 if(i == 5) attron(COLOR_PAIR(colourpair_magenta));
358
359 sprintf(buffer, "%c", title[i]);
360 mvprintw(2, x, "%s", buffer);
361 x +=2;
362 }
363 attroff(COLOR_PAIR(colourpair_red));
364 attroff(A_BOLD);
365
366 /* Display menu title */
367 y = 4;
368 x = (display_size_x / 2) - utf8strlen(pmenu->title);
369
370 attron(A_BOLD);
371 attroff(COLOR_PAIR(colourpair_white));
372 /* If the title is too long, plot normally */
373 if(x < 0)
374 {
375 x = (display_size_x - utf8strlen(pmenu->title)) / 2;
376 mvprintw(y, x, "%s", pmenu->title);
377 }
378 else
379 {
380 /* Otherwise, spread it out */
381 for(i = 0; i < strlen(pmenu->title); i ++)
382 {
383 j = 0;
384 buffer[j] = pmenu->title[i]; j ++;
385 while((pmenu->title[i + j] & 0xc0) == 0x80)
386 {
387 buffer[j] = pmenu->title[i + j]; j ++;
388 }
389 buffer[j] = 0;
390 mvprintw(y, x, "%s", buffer);
391 x += 2; i += j - 1;
392 }
393 }
394 attroff(A_BOLD);
395 }
396 }
397
398 /* Keep scroll bar within reasonable limits */
399 if(pmenu->offset > (menu_height_entries - (menu_y_max - menu_y_min)))
400 pmenu->offset = menu_height_entries - (menu_y_max - menu_y_min);
401 if(pmenu->offset < 0)
402 pmenu->offset = 0;
403
404 /* Display scrollbar, if needed */
405 if(menu_height_entries > (menu_y_max - menu_y_min) || pmenu->offset != 0)
406 {
407 if(redraw >= MENUREDRAW_ENTRIES)
408 {
409 menu_scroll_y_min = menu_y_min + 1;
410 menu_scroll_y_max = menu_y_max - 1;
411 menu_scroll_top = menu_scroll_y_min + ((menu_scroll_y_max - menu_scroll_y_min) * pmenu->offset / menu_height_entries);
412 menu_scroll_bottom = menu_scroll_top + ((menu_scroll_y_max - menu_scroll_y_min) * (1 + menu_y_max - menu_y_min) / menu_height_entries);
413
414 attron(COLOR_PAIR(colourpair_menugrey));
415 x = menu_offset + menu_width + 1;
416 mvaddch(menu_y_min, x, '^');
417 mvaddch(menu_y_max - 1, x, 'v');
418
419 attron(COLOR_PAIR(colourpair_white));
420 for(y = menu_y_min + 1; y < menu_y_max - 1; y ++)
421 {
422 /* >= and <= to guarantee at least one character scrollbar */
423 if(y >= menu_scroll_top && y <= menu_scroll_bottom)
424 {
425 attron(A_REVERSE);
426 mvaddch(y, x, '|');
427 attroff(A_REVERSE);
428 }
429 else
430 mvaddch(y, x, '.');
431 }
432 }
433 }
434
435 /* Display notes */
436 if((menu_height_notes != 0) && redraw >= MENUREDRAW_ENTRIES)
437 {
438 if(pmenu->logo)
439 y = menu_y_logo_bottom;
440 else
441 y = menu_y_max + 1;
442
443 pentry = pmenu->entry_first;
444 while(pentry != NULL)
445 {
446 if(pentry->flags & MENU_NOTE)
447 {
448 menu_displayentry(pmenu, pentry, y, 0);
449 y += menu_entryheight(pentry);
450 }
451 pentry = pentry->next;
452 }
453 }
454
455 /* Select an entry if the selected one is not on screen */
456 if(pmenu->entry_selected == NULL)
457 pmenu->entry_selected = pmenu->entry_first;
458 y = menu_y_min - pmenu->offset;
459 pentry = pmenu->entry_first;
460 pmenu->display_first = NULL;
461 pmenu->display_last = NULL;
462 state = 1;
463 while(pentry != NULL)
464 {
465 /* Don't count notes */
466 if(pentry->flags & MENU_NOTE)
467 {
468 pentry = pentry->next;
469 continue;
470 }
471 /* Is the entry off the top of the screen? */
472 if(y < (menu_y_min - menu_entryheight(pentry)))
473 {
474 if(pentry == pmenu->entry_selected)
475 state = -1;
476 y += menu_entryheight(pentry);
477 pentry = pentry->next;
478 continue;
479 }
480 /* Stop processing once we hit the bottom of the screen */
481 if(y > menu_y_max)
482 {
483 pentry = NULL;
484 continue;
485 }
486 if(pentry == pmenu->entry_selected)
487 state = 0;
488
489 if(pmenu->display_first == NULL)
490 pmenu->display_first = pentry->next;
491 pmenu->display_last = pentry->previous;
492
493 y += menu_entryheight(pentry);
494 pentry = pentry->next;
495 }
496 if(state == -1)
497 pmenu->entry_selected = pmenu->display_first;
498 if(state == 1)
499 pmenu->entry_selected = pmenu->display_last;
500 if(state != 0 && redraw < MENUREDRAW_ENTRIES)
501 redraw = MENUREDRAW_ENTRIES;
502
503 /* Display entries */
504 pentry = pmenu->entry_first;
505 y = menu_y_min - pmenu->offset;
506 y_editing = 0;
507 while(pentry != NULL)
508 {
509 /* Don't display notes */
510 if(pentry->flags & MENU_NOTE)
511 {
512 pentry = pentry->next;
513 continue;
514 }
515 /* Don't display entries off the top of the screen */
516 if(y < (menu_y_min - menu_entryheight(pentry)))
517 {
518 y += menu_entryheight(pentry);
519 pentry = pentry->next;
520 continue;
521 }
522 /* Stop processing once we hit the bottom of the screen */
523 if(y > menu_y_max)
524 {
525 pentry = NULL;
526 continue;
527 }
528 selected = (pmenu->entry_selected == pentry) ? 1 : 0;
529
530 if(redraw >= MENUREDRAW_ENTRIES ||
531 (redraw >= MENUREDRAW_CHANGED && pentry->redraw))
532 menu_displayentry(pmenu, pentry, y, selected);
533 if(pentry->flags & MENU_EDITING)
534 y_editing = y + 1;
535
536
537 pentry->redraw = 0;
538 y += menu_entryheight(pentry);
539 pentry = pentry->next;
540 }
541
542 /* Display cursor if we're editing a text field */
543 if(y_editing)
544 {
545 curs_set(1);
546 move(y_editing, menu_offset + menu_width - 2);
547 }
548 else
549 curs_set(0);
550
551 /* Redraw the screen */
552 refresh();
553 }
554
menu_process(struct menu * pmenu)555 int menu_process(struct menu* pmenu)
556 {
557 int ok;
558 int redraw;
559 int c;
560 struct menuentry* pentry;
561 char *buffer;
562
563 redraw = pmenu->redraw;
564
565 ok = 0;
566 while(!ok)
567 {
568 if(redraw != MENUREDRAW_NONE)
569 {
570 menu_display(pmenu, redraw);
571 redraw = MENUREDRAW_NONE;
572 }
573
574 c = getch();
575
576 /* Are we editing a text field? */
577 if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_EDITING)
578 {
579 switch(c)
580 {
581 case KEY_RESIZE:
582 getmaxyx(stdscr, display_size_y, display_size_x);
583 redraw = MENUREDRAW_ALL;
584 break;
585
586 case '\n':
587 case '\r':
588 case 27:
589 case KEY_UP:
590 case KEY_DOWN:
591 case KEY_PPAGE:
592 case KEY_NPAGE:
593 pmenu->entry_selected->flags -= MENU_EDITING;
594 pmenu->entry_selected->redraw = 1;
595 redraw = MENUREDRAW_CHANGED;
596 break;
597
598 case KEY_BACKSPACE:
599 case KEY_DC:
600 case 8:
601 if(strlen(pmenu->entry_selected->text4) == 0)
602 break;
603
604 buffer = malloc(strlen(pmenu->entry_selected->text4) + 1);
605 if(buffer != NULL)
606 {
607 strcpy(buffer, pmenu->entry_selected->text4);
608
609 /* not particularly efficient, but does the job of deleting one UTF8 character */
610 while(strlen(buffer) > 0 && ((buffer[strlen(buffer) - 1] & 0xc0) == 0x80))
611 buffer[strlen(buffer) - 1] = 0;
612 buffer[strlen(buffer) - 1] = 0;
613 }
614 menuentry_extratext(pmenu->entry_selected, NULL, NULL, buffer);
615 free(buffer);
616
617 pmenu->entry_selected->redraw = 1;
618 redraw = MENUREDRAW_CHANGED;
619 break;
620
621 default:
622 if(c > 31 && c != 127)
623 {
624 buffer = malloc(strlen(pmenu->entry_selected->text4) + 2);
625 if(buffer != NULL)
626 {
627 strcpy(buffer, pmenu->entry_selected->text4);
628 buffer[strlen(buffer) + 1] = 0;
629 buffer[strlen(buffer)] = c;
630 }
631 menuentry_extratext(pmenu->entry_selected, NULL, NULL, buffer);
632 free(buffer);
633
634 pmenu->entry_selected->redraw = 1;
635 redraw = MENUREDRAW_CHANGED;
636 break;
637 }
638 break;
639 }
640 continue;
641 }
642
643 /* Not a text field, but a regular entry */
644 /* First, check if the key corresponds to an entry */
645 if(c >= 0 && c < 127)
646 c = toupper(c);
647 pentry = pmenu->entry_first;
648 while(pentry != NULL)
649 {
650 if(pentry->key == c)
651 {
652 if(!(pentry->flags & (MENU_GREY | MENU_INVISIBLE | MENU_SPACE)))
653 {
654 if(pmenu->entry_selected != NULL)
655 pmenu->entry_selected->redraw = 1;
656 pmenu->entry_selected = pentry;
657 pentry->redraw = 1;
658
659 if(pmenu->entry_selected->flags & MENU_EDITABLE)
660 {
661 pmenu->entry_selected->flags |= MENU_EDITING;
662 pmenu->entry_selected->redraw = 1;
663 redraw = MENUREDRAW_CHANGED;
664 }
665 else
666 ok = MENU_SELECT;
667 break;
668 }
669 }
670 pentry = pentry->next;
671 }
672
673 if(ok == MENU_SELECT)
674 continue;
675
676 if(c < 0)
677 continue;
678
679 /* Otherwise, see if it corresponds to an action */
680 switch(actions[c])
681 {
682 case ACTION_UP:
683 pentry = pmenu->entry_selected;
684 while(pentry != NULL)
685 {
686 if(pentry == pmenu->display_first || pentry->flags & MENU_TEXT)
687 redraw = MENUREDRAW_ENTRIES;
688
689 pentry = pentry->previous;
690
691 if(pentry == NULL)
692 break;
693 if(redraw != MENUREDRAW_NONE)
694 pmenu->offset -= menu_entryheight(pentry);
695 if(!(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE)))
696 break;
697 }
698 if(pentry != NULL)
699 {
700 pentry->redraw = 1;
701 pmenu->entry_selected->redraw = 1;
702 pmenu->entry_selected = pentry;
703 if(redraw == MENUREDRAW_NONE)
704 redraw = MENUREDRAW_CHANGED;
705 }
706 break;
707
708 case ACTION_DOWN:
709 pentry = pmenu->entry_selected;
710 while(pentry != NULL)
711 {
712 if(pentry == pmenu->display_last || pentry->flags & MENU_TEXT)
713 redraw = MENUREDRAW_ENTRIES;
714
715 pentry = pentry->next;
716
717 if(pentry == NULL)
718 break;
719 if(redraw != MENUREDRAW_NONE)
720 pmenu->offset += menu_entryheight(pentry);
721 if(!(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE)))
722 break;
723 }
724 if(pentry != NULL)
725 {
726 pentry->redraw = 1;
727 pmenu->entry_selected->redraw = 1;
728 pmenu->entry_selected = pentry;
729 if(redraw == MENUREDRAW_NONE)
730 redraw = MENUREDRAW_CHANGED;
731 }
732 break;
733
734 case ACTION_LEFT:
735 if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_SCROLLABLE)
736 ok = MENU_SCROLLLEFT;
737 break;
738
739 case ACTION_RIGHT:
740 if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_SCROLLABLE)
741 ok = MENU_SCROLLRIGHT;
742 break;
743
744 case ACTION_PAGE_UP:
745 pmenu->offset -= (menu_y_max - menu_y_min);
746 redraw = MENUREDRAW_ENTRIES;
747 break;
748
749 case ACTION_PAGE_DOWN:
750 pmenu->offset += (menu_y_max - menu_y_min);
751 redraw = MENUREDRAW_ENTRIES;
752 break;
753
754 case ACTION_ENTER:
755 if(pmenu->entry_selected != NULL)
756 {
757 if(pmenu->entry_selected->flags & MENU_EDITABLE)
758 {
759 pmenu->entry_selected->flags |= MENU_EDITING;
760 pmenu->entry_selected->redraw = 1;
761 redraw = MENUREDRAW_CHANGED;
762 }
763 else
764 ok = MENU_SELECT;
765 }
766 break;
767
768 case ACTION_DELETE:
769 if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_DELETABLE)
770 ok = MENU_DELETE;
771 break;
772
773 case ACTION_QUIT:
774 ok = MENU_QUIT;
775 break;
776
777 case ACTION_REDRAW:
778 getmaxyx(stdscr, display_size_y, display_size_x);
779 redraw = MENUREDRAW_ALL;
780 break;
781
782 case ACTION_HIDE:
783 display_hide();
784 redraw = MENUREDRAW_ALL;
785 break;
786
787 default:
788 /* See if there is an "any key" entry */
789 pentry = pmenu->entry_first;
790 while(pentry != NULL)
791 {
792 if(pentry->key == MENU_KEY_ANY)
793 {
794 if(!(pentry->flags & (MENU_GREY | MENU_INVISIBLE | MENU_SPACE)))
795 {
796 if(pmenu->entry_selected != NULL)
797 pmenu->entry_selected->redraw = 1;
798 pmenu->entry_selected = pentry;
799 pentry->redraw = 1;
800
801 ok = MENU_SELECT;
802 break;
803 }
804 }
805 pentry = pentry->next;
806 }
807 break;
808 }
809 }
810
811 /* Redraw the whole menu when we next process it */
812 pmenu->redraw = MENUREDRAW_ALL;
813
814 if(ok == MENU_SELECT)
815 {
816 if(pmenu->entry_selected->flags & MENU_SCROLLABLE)
817 ok = MENU_SCROLLRIGHT;
818 }
819 /* unless this is a scrollable entry */
820 if(ok == MENU_SCROLLLEFT || ok == MENU_SCROLLRIGHT)
821 {
822 pmenu->redraw = MENUREDRAW_CHANGED;
823 pmenu->entry_selected->redraw = 1;
824 }
825
826 return ok;
827 }
828
menu_addfile(struct menu * pmenu,char * filename)829 int menu_addfile(struct menu *pmenu, char *filename)
830 {
831 FILE *file;
832 char word[256], buffer[4096];
833 char c;
834 int i;
835 int ok, wok;
836
837 file = fopen(filename, "r");
838 if(file == NULL)
839 return 0;
840
841 ok = 0;
842 strcpy(buffer, "");
843 while(!ok)
844 {
845 wok = 0; i = 0;
846 while(!wok)
847 {
848 c = fgetc(file);
849 if(c == 0 || c == 13 || c == 10 || c == 32 || c == 9 || feof(file) || i == 254)
850 wok = 1;
851 else
852 word[i++] = c;
853 }
854 word[i] = 0;
855
856 /* We assume menu_width is defined by the time we get here - a safe
857 assumption provided this isn't the first menu we see. */
858 if(utf8strlen(buffer) + utf8strlen(word) < menu_width - 2 && !(strcmp(word, "") == 0 && (c == 10 || c == 13)) && !(strncmp(word, "===", 3) == 0))
859 {
860 if(buffer[0] != 0 && word[0] != 0)
861 strcat(buffer, " ");
862 strcat(buffer, word);
863 }
864 else
865 {
866 menuentry_new(pmenu, buffer, 0, MENU_TEXT);
867 if(strcmp(word, "") == 0 && (c == 10 || c ==13))
868 menuentry_new(pmenu, "", 0, MENU_TEXT);
869 if(strncmp(word, "===", 3) == 0)
870 {
871 strcpy(buffer, "");
872 pmenu->entry_last->flags |= MENU_GREY;
873 }
874 else
875 strcpy(buffer, word);
876 }
877
878 if(feof(file))
879 ok = 1;
880 }
881
882 menuentry_new(pmenu, buffer, 0, MENU_TEXT);
883
884 fclose(file);
885
886 return 1;
887 }
888