1
2
3
4
5
6
7
8
9
10
11
12
13#include "menu.h"
14#include "com32io.h"
15#include <stdlib.h>
16#include <console.h>
17
18
19static pt_menusystem ms;
20char TITLESTR[] =
21 "COMBOOT Menu System for SYSLINUX developed by Murali Krishnan Ganapathy";
22char TITLELONG[] = " TITLE too long ";
23char ITEMLONG[] = " ITEM too long ";
24char ACTIONLONG[] = " ACTION too long ";
25char STATUSLONG[] = " STATUS too long ";
26char EMPTYSTR[] = "";
27
28
29int calc_visible(pt_menu menu, int first);
30int next_visible(pt_menu menu, int index);
31int prev_visible(pt_menu menu, int index);
32int next_visible_sep(pt_menu menu, int index);
33int prev_visible_sep(pt_menu menu, int index);
34int calc_first_early(pt_menu menu, int curr);
35int calc_first_late(pt_menu menu, int curr);
36int isvisible(pt_menu menu, int first, int curr);
37
38
39
40
41
42
43static int getch(void)
44{
45 t_timeout_handler th;
46 int key;
47 unsigned long i;
48
49
50 if ((ms->ontimeout == NULL) && (ms->ontotaltimeout == NULL))
51 return get_key(stdin, 0);
52
53 th = ms->ontimeout;
54 for (;;) {
55 for (i = 0; i < ms->tm_numsteps; i++) {
56 key = get_key(stdin, ms->tm_stepsize);
57 if (key != KEY_NONE)
58 return key;
59
60 if ((ms->tm_total_timeout == 0) || (ms->ontotaltimeout == NULL))
61 continue;
62 ms->tm_sofar_timeout += ms->tm_stepsize;
63 if (ms->tm_sofar_timeout >= ms->tm_total_timeout) {
64 th = ms->ontotaltimeout;
65 ms->tm_sofar_timeout = 0;
66 break;
67 }
68 }
69 if (!th)
70 continue;
71 key = th();
72 switch (key) {
73 case CODE_ENTER:
74 return KEY_ENTER;
75 case CODE_ESCAPE:
76 return KEY_ESC;
77 default:
78 break;
79 }
80 }
81 return KEY_NONE;
82}
83
84int find_shortcut(pt_menu menu, uchar shortcut, int index)
85
86{
87 int ans;
88 pt_menuitem mi;
89
90
91 if ((index < 0) || (index >= menu->numitems))
92 return index;
93 ans = index + 1;
94
95 while (ans < menu->numitems) {
96 mi = menu->items[ans];
97 if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP)
98 || (mi->shortcut != shortcut))
99 ans++;
100 else
101 return ans;
102 }
103
104 ans = 0;
105 while (ans < index) {
106 mi = menu->items[ans];
107 if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP)
108 || (mi->shortcut != shortcut))
109 ans++;
110 else
111 return ans;
112 }
113 return index;
114}
115
116
117static void reset_ui(void)
118{
119 uchar tpos;
120
121 cls();
122 clearwindow(ms->minrow, ms->mincol, ms->maxrow, ms->maxcol,
123 ms->fillchar, ms->fillattr);
124
125 tpos = (ms->numcols - strlen(ms->title) - 1) >> 1;
126 gotoxy(ms->minrow, ms->mincol);
127 cprint(ms->tfillchar, ms->titleattr, ms->numcols);
128 gotoxy(ms->minrow, ms->mincol + tpos);
129 csprint(ms->title, ms->titleattr);
130
131 cursoroff();
132}
133
134
135
136
137
138
139void printmenuitem(const char *str, uchar * attr)
140{
141 int hlite = NOHLITE;
142
143 while (*str) {
144 switch (*str) {
145 case BELL:
146 break;
147 case ENABLEHLITE:
148 hlite = HLITE;
149 break;
150 case DISABLEHLITE:
151 hlite = NOHLITE;
152 break;
153 default:
154 putch(*str, attr[hlite]);
155 }
156 str++;
157 }
158}
159
160
161
162
163
164
165
166
167
168
169
170
171static void print_line(pt_menu menu, int curr, uchar top, uchar left,
172 int x, int row, bool radio)
173{
174 pt_menuitem ci;
175 char fchar[6], lchar[6];
176 const char *str;
177 char sep[MENULEN];
178 uchar *attr;
179 int menuwidth = menu->menuwidth + 3;
180
181 if (row >= menu->menuheight)
182 return;
183
184 ci = menu->items[x];
185
186 memset(sep, ms->box_horiz, menuwidth);
187 sep[menuwidth - 1] = 0;
188
189
190 if (radio) {
191 fchar[0] = '\b';
192 fchar[1] = SO;
193 fchar[2] = (x == curr ? RADIOSEL : RADIOUNSEL);
194 fchar[3] = SI;
195 fchar[4] = '\0';
196 lchar[0] = '\0';
197 attr = ms->normalattr;
198 } else {
199 lchar[0] = fchar[0] = ' ';
200 lchar[1] = fchar[1] = '\0';
201 attr = (x == curr ? ms->reverseattr : ms->normalattr);
202 }
203 str = ci->item;
204 switch (ci->action)
205 {
206 case OPT_INACTIVE:
207 if (radio)
208 attr = ms->inactattr;
209 else
210 attr = (x == curr ? ms->revinactattr : ms->inactattr);
211 break;
212 case OPT_SUBMENU:
213 if (radio)
214 break;
215 lchar[0] = '>';
216 lchar[1] = 0;
217 break;
218 case OPT_RADIOMENU:
219 if (radio)
220 break;
221 lchar[0] = RADIOMENUCHAR;
222 lchar[1] = 0;
223 break;
224 case OPT_CHECKBOX:
225 if (radio)
226 break;
227 lchar[0] = '\b';
228 lchar[1] = SO;
229 lchar[2] = (ci->itemdata.checked ? CHECKED : UNCHECKED);
230 lchar[3] = SI;
231 lchar[4] = 0;
232 break;
233 case OPT_SEP:
234 fchar[0] = '\b';
235 fchar[1] = SO;
236 fchar[2] = LEFT_MIDDLE_BORDER;
237 fchar[3] = MIDDLE_BORDER;
238 fchar[4] = MIDDLE_BORDER;
239 fchar[5] = 0;
240 memset(sep, MIDDLE_BORDER, menuwidth);
241 sep[menuwidth - 1] = 0;
242 str = sep;
243 lchar[0] = MIDDLE_BORDER;
244 lchar[1] = RIGHT_MIDDLE_BORDER;
245 lchar[2] = SI;
246 lchar[3] = 0;
247 break;
248 case OPT_EXITMENU:
249 if (radio)
250 break;
251 fchar[0] = '<';
252 fchar[1] = 0;
253 break;
254 default:
255 break;
256 }
257
258
259 gotoxy(top + row, left - 2);
260 cprint(ms->spacechar, attr[NOHLITE], menuwidth + 2);
261
262
263 gotoxy(top + row, left - 2);
264 csprint(fchar, attr[NOHLITE]);
265
266
267 gotoxy(top + row, left);
268 printmenuitem(str, attr);
269
270
271 gotoxy(top + row, left + menuwidth - 1);
272 csprint(lchar, attr[NOHLITE]);
273}
274
275
276
277static void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first, bool radio)
278{
279 int x, row;
280 int numitems, menuwidth;
281 pt_menuitem ci;
282
283 numitems = calc_visible(menu, first);
284 if (numitems > menu->menuheight)
285 numitems = menu->menuheight;
286
287 menuwidth = menu->menuwidth + 3;
288 clearwindow(top, left - 2, top + numitems + 1, left + menuwidth + 1,
289 ms->fillchar, ms->shadowattr);
290 drawbox(top - 1, left - 3, top + numitems, left + menuwidth,
291 ms->normalattr[NOHLITE]);
292
293
294 x = (menuwidth - strlen(menu->title) - 1) >> 1;
295 gotoxy(top - 1, left + x);
296 printmenuitem(menu->title, ms->normalattr);
297
298
299 row = -1;
300 for (x = first; x < menu->numitems; x++) {
301 ci = menu->items[x];
302 if (ci->action == OPT_INVISIBLE)
303 continue;
304 row++;
305 if (row >= numitems)
306 break;
307 print_line(menu, curr, top, left, x, row, radio);
308 }
309
310
311 row = 0;
312 x = next_visible_sep(menu, 0);
313 if (!isvisible(menu, first, x))
314 {
315 row = 1;
316 gotoxy(top, left + menuwidth);
317 cprint(MOREABOVE, ms->normalattr[NOHLITE], 1);
318 }
319 x = prev_visible_sep(menu, menu->numitems);
320 if (!isvisible(menu, first, x))
321 {
322 row = 1;
323 gotoxy(top + numitems - 1, left + menuwidth);
324 cprint(MOREBELOW, ms->normalattr[NOHLITE], 1);
325 }
326
327 x = ((numitems - 1) * curr) / (menu->numitems);
328 if ((x > 0) && (row == 1)) {
329 gotoxy(top + x, left + menuwidth);
330 csprint("\016\141\017", ms->normalattr[NOHLITE]);
331 }
332 if (ms->handler)
333 ms->handler(ms, menu->items[curr]);
334}
335
336void cleanupmenu(pt_menu menu, uchar top, uchar left, int numitems)
337{
338 if (numitems > menu->menuheight)
339 numitems = menu->menuheight;
340 clearwindow(top, left - 2, top + numitems + 1, left + menu->menuwidth + 4, ms->fillchar, ms->fillattr);
341 clearwindow(top - 1, left - 3, top + numitems, left + menu->menuwidth + 3, ms->fillchar, ms->fillattr);
342}
343
344
345
346static pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar startopt, bool radio)
347
348{
349 int prev, prev_first, curr, i, first, tmp;
350 int asc = 0;
351 bool redraw = true;
352 uchar numitems;
353 pt_menuitem ci;
354 t_handler_return hr;
355
356 numitems = calc_visible(menu, 0);
357
358 gotoxy(ms->minrow + ms->statline, ms->mincol);
359 cprint(ms->spacechar, ms->statusattr[NOHLITE], ms->numcols);
360
361
362 curr = next_visible(menu, startopt);
363 prev = curr;
364
365 gotoxy(ms->minrow + ms->statline, ms->mincol);
366 cprint(ms->spacechar, ms->statusattr[NOHLITE], ms->numcols);
367 gotoxy(ms->minrow + ms->statline, ms->mincol);
368 printmenuitem(menu->items[curr]->status, ms->statusattr);
369 first = calc_first_early(menu, curr);
370 prev_first = first;
371 while (1)
372 {
373
374
375
376
377 if (prev_first != first || redraw) {
378 printmenu(menu, curr, top, left, first, radio);
379 } else {
380
381 print_line(menu, curr, top, left, prev, prev - first, radio);
382 print_line(menu, curr, top, left, curr, curr - first, radio);
383 }
384 redraw = false;
385 prev = curr;
386 prev_first = first;
387 ci = menu->items[curr];
388 asc = getch();
389 switch (asc) {
390 case KEY_CTRL('L'):
391 redraw = true;
392 break;
393 case KEY_HOME:
394 curr = next_visible(menu, 0);
395 first = calc_first_early(menu, curr);
396 break;
397 case KEY_END:
398 curr = prev_visible(menu, numitems - 1);
399 first = calc_first_late(menu, curr);
400 break;
401 case KEY_PGDN:
402 for (i = 0; i < 5; i++)
403 curr = next_visible(menu, curr + 1);
404 first = calc_first_late(menu, curr);
405 break;
406 case KEY_PGUP:
407 for (i = 0; i < 5; i++)
408 curr = prev_visible(menu, curr - 1);
409 first = calc_first_early(menu, curr);
410 break;
411 case KEY_UP:
412 curr = prev_visible(menu, curr - 1);
413 if (curr < first)
414 first = calc_first_early(menu, curr);
415 break;
416 case KEY_DOWN:
417 curr = next_visible(menu, curr + 1);
418 if (!isvisible(menu, first, curr))
419 first = calc_first_late(menu, curr);
420 break;
421 case KEY_LEFT:
422 case KEY_ESC:
423 return NULL;
424 break;
425 case KEY_RIGHT:
426 case KEY_ENTER:
427 if (ci->action == OPT_INACTIVE)
428 break;
429 if (ci->action == OPT_CHECKBOX)
430 break;
431 if (ci->action == OPT_SEP)
432 break;
433 if (ci->action == OPT_EXITMENU)
434 return NULL;
435
436 if (ci->action == OPT_RADIOMENU)
437 return ci;
438 if (ci->handler != NULL)
439 {
440 hr = ci->handler(ms, ci);
441 if (hr.refresh)
442 {
443
444 cleanupmenu(menu, top, left, numitems);
445
446 numitems = calc_visible(menu, 0);
447
448 printmenu(menu, curr, top, left, first, radio);
449 }
450 if (hr.valid)
451 return ci;
452 } else
453 return ci;
454 break;
455 case SPACECHAR:
456 if (ci->action != OPT_CHECKBOX)
457 break;
458 ci->itemdata.checked = !ci->itemdata.checked;
459 if (ci->handler != NULL)
460 {
461 hr = ci->handler(ms, ci);
462 if (hr.refresh)
463 {
464
465 cleanupmenu(menu, top, left, numitems);
466
467 numitems = calc_visible(menu, 0);
468
469 printmenu(menu, curr, top, left, first, radio);
470 }
471 }
472 break;
473 default:
474
475 if (((asc >= 'A') && (asc <= 'Z')) ||
476 ((asc >= 'a') && (asc <= 'z')) ||
477 ((asc >= '0') && (asc <= '9'))) {
478 tmp = find_shortcut(menu, asc, curr);
479 if ((tmp > curr) && (!isvisible(menu, first, tmp)))
480 first = calc_first_late(menu, tmp);
481 if (tmp < curr)
482 first = calc_first_early(menu, tmp);
483 curr = tmp;
484 } else {
485 if (ms->keys_handler)
486 ms->keys_handler(ms, menu->items[curr], asc);
487
488
489 reset_ui();
490
491 cleanupmenu(menu, top, left, numitems);
492
493 numitems = calc_visible(menu, 0);
494
495 printmenu(menu, curr, top, left, first, radio);
496 }
497 break;
498 }
499
500
501 gotoxy(ms->minrow + ms->statline, ms->mincol);
502 cprint(ms->spacechar, ms->statusattr[NOHLITE], ms->numcols);
503
504 gotoxy(ms->minrow + ms->statline, ms->mincol);
505 printmenuitem(menu->items[curr]->status, ms->statusattr);
506 }
507 return NULL;
508}
509
510
511pt_menuitem runmenusystem(uchar top, uchar left, pt_menu cmenu, uchar startopt,
512 uchar menutype)
513
514
515
516
517
518
519
520
521
522
523
524
525
526{
527 pt_menuitem opt, choice;
528 uchar startat, mt;
529 uchar row, col;
530
531 if (cmenu == NULL)
532 return NULL;
533
534startover:
535
536 cmenu->menuheight = ms->maxrow - top - 3;
537 if (cmenu->menuheight > ms->maxmenuheight)
538 cmenu->menuheight = ms->maxmenuheight;
539 if (menutype == NORMALMENU)
540 opt = getmenuoption(cmenu, top, left, startopt, false);
541 else
542 opt = getmenuoption(cmenu, top, left, startopt, true);
543
544 if (opt == NULL) {
545
546 cleanupmenu(cmenu, top, left, calc_visible(cmenu, 0));
547 return NULL;
548 }
549
550 if ((opt->action != OPT_SUBMENU) && (opt->action != OPT_RADIOMENU)) {
551 cleanupmenu(cmenu, top, left, calc_visible(cmenu, 0));
552 return opt;
553 }
554
555
556
557 if (opt->itemdata.submenunum >= ms->nummenus)
558 {
559 gotoxy(12, 12);
560 csprint("ERROR: Invalid submenu requested.", 0x07);
561 cleanupmenu(cmenu, top, left, calc_visible(cmenu, 0));
562 return NULL;
563 }
564
565
566
567 row = ms->menus[(unsigned int)opt->itemdata.submenunum]->row;
568 col = ms->menus[(unsigned int)opt->itemdata.submenunum]->col;
569 if (row == 0xFF)
570 row = top + opt->index + 2;
571 if (col == 0xFF)
572 col = left + 3 + (cmenu->menuwidth >> 1);
573 mt = (opt->action == OPT_SUBMENU ? NORMALMENU : RADIOMENU);
574 startat = 0;
575 if ((opt->action == OPT_RADIOMENU) && (opt->data != NULL))
576 startat = ((t_menuitem *) opt->data)->index;
577
578 choice = runmenusystem(row, col,
579 ms->menus[(unsigned int)opt->itemdata.submenunum],
580 startat, mt);
581 if (opt->action == OPT_RADIOMENU) {
582 if (choice != NULL)
583 opt->data = (void *)choice;
584 if (opt->handler != NULL)
585 opt->handler(ms, opt);
586 choice = NULL;
587 }
588 if (choice == NULL)
589 {
590
591 startopt = opt->index;
592 goto startover;
593 } else {
594 cleanupmenu(cmenu, top, left, calc_visible(cmenu, 0));
595 return choice;
596 }
597}
598
599
600uchar find_menu_num(const char *name)
601{
602 int i;
603 pt_menu m;
604
605 if (name == NULL)
606 return (uchar) (-1);
607 for (i = 0; i < ms->nummenus; i++) {
608 m = ms->menus[i];
609 if ((m->name) && (strcmp(m->name, name) == 0))
610 return i;
611 }
612 return (uchar) (-1);
613}
614
615
616
617
618void fix_submenus(void)
619{
620 int i, j;
621 pt_menu m;
622 pt_menuitem mi;
623
624 i = 0;
625 for (i = 0; i < ms->nummenus; i++) {
626 m = ms->menus[i];
627 for (j = 0; j < m->numitems; j++) {
628 mi = m->items[j];
629
630 if (mi->data && strlen(mi->data) > 0 &&
631 ((mi->action == OPT_SUBMENU)
632 || (mi->action == OPT_RADIOMENU))) {
633 mi->itemdata.submenunum = find_menu_num(mi->data);
634 }
635 }
636 }
637}
638
639
640
641pt_menuitem showmenus(uchar startmenu)
642{
643 pt_menuitem rv;
644
645 fix_submenus();
646
647
648 printf(CSI "?7l");
649
650
651 reset_ui();
652
653
654 rv = runmenusystem(ms->minrow + MENUROW, ms->mincol + MENUCOL,
655 ms->menus[(unsigned int)startmenu], 0, NORMALMENU);
656
657
658 cls();
659 gotoxy(ms->minrow, ms->mincol);
660 cursoron();
661
662
663 return rv;
664}
665
666pt_menusystem init_menusystem(const char *title)
667{
668 int i;
669
670 ms = NULL;
671 ms = (pt_menusystem) malloc(sizeof(t_menusystem));
672 if (ms == NULL)
673 return NULL;
674 ms->nummenus = 0;
675
676 for (i = 0; i < MAXMENUS; i++)
677 ms->menus[i] = NULL;
678
679 ms->title = (char *)malloc(TITLELEN + 1);
680 if (title == NULL)
681 strcpy(ms->title, TITLESTR);
682 else
683 strcpy(ms->title, title);
684
685
686 ms->tm_stepsize = TIMEOUTSTEPSIZE;
687 ms->tm_numsteps = TIMEOUTNUMSTEPS;
688
689 ms->normalattr[NOHLITE] = NORMALATTR;
690 ms->normalattr[HLITE] = NORMALHLITE;
691
692 ms->reverseattr[NOHLITE] = REVERSEATTR;
693 ms->reverseattr[HLITE] = REVERSEHLITE;
694
695 ms->inactattr[NOHLITE] = INACTATTR;
696 ms->inactattr[HLITE] = INACTHLITE;
697
698 ms->revinactattr[NOHLITE] = REVINACTATTR;
699 ms->revinactattr[HLITE] = REVINACTHLITE;
700
701 ms->statusattr[NOHLITE] = STATUSATTR;
702 ms->statusattr[HLITE] = STATUSHLITE;
703
704 ms->statline = STATLINE;
705 ms->tfillchar = TFILLCHAR;
706 ms->titleattr = TITLEATTR;
707
708 ms->fillchar = FILLCHAR;
709 ms->fillattr = FILLATTR;
710 ms->spacechar = SPACECHAR;
711 ms->shadowattr = SHADOWATTR;
712
713 ms->menupage = MENUPAGE;
714
715
716 ms->handler = NULL;
717 ms->keys_handler = NULL;
718 ms->ontimeout = NULL;
719 ms->tm_total_timeout = 0;
720 ms->tm_sofar_timeout = 0;
721 ms->ontotaltimeout = NULL;
722
723
724 ACTION_VALID.valid = 1;
725 ACTION_VALID.refresh = 0;
726 ACTION_INVALID.valid = 0;
727 ACTION_INVALID.refresh = 0;
728
729
730
731 if (getscreensize(1, &ms->numrows, &ms->numcols)) {
732
733 ms->numcols = 80;
734 ms->numrows = 24;
735 }
736 ms->minrow = ms->mincol = 0;
737 ms->maxcol = ms->numcols - 1;
738 ms->maxrow = ms->numrows - 1;
739
740
741 ms->maxmenuheight = ms->maxrow - ms->minrow - 3;
742 if (ms->maxmenuheight > MAXMENUHEIGHT)
743 ms->maxmenuheight = MAXMENUHEIGHT;
744
745 console_ansi_raw();
746
747 return ms;
748}
749
750void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal,
751 uchar inactiveselected)
752{
753 if (normal != 0xFF)
754 ms->normalattr[0] = normal;
755 if (selected != 0xFF)
756 ms->reverseattr[0] = selected;
757 if (inactivenormal != 0xFF)
758 ms->inactattr[0] = inactivenormal;
759 if (inactiveselected != 0xFF)
760 ms->revinactattr[0] = inactiveselected;
761}
762
763void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal,
764 uchar inactiveselected)
765{
766 if (normal != 0xFF)
767 ms->normalattr[1] = normal;
768 if (selected != 0xFF)
769 ms->reverseattr[1] = selected;
770 if (inactivenormal != 0xFF)
771 ms->inactattr[1] = inactivenormal;
772 if (inactiveselected != 0xFF)
773 ms->revinactattr[1] = inactiveselected;
774}
775
776void set_status_info(uchar statusattr, uchar statushlite, uchar statline)
777{
778 if (statusattr != 0xFF)
779 ms->statusattr[NOHLITE] = statusattr;
780 if (statushlite != 0xFF)
781 ms->statusattr[HLITE] = statushlite;
782
783 if (statline >= ms->numrows)
784 statline = ms->numrows - 1;
785 ms->statline = statline;
786}
787
788void set_title_info(uchar tfillchar, uchar titleattr)
789{
790 if (tfillchar != 0xFF)
791 ms->tfillchar = tfillchar;
792 if (titleattr != 0xFF)
793 ms->titleattr = titleattr;
794}
795
796void set_misc_info(uchar fillchar, uchar fillattr, uchar spacechar,
797 uchar shadowattr)
798{
799 if (fillchar != 0xFF)
800 ms->fillchar = fillchar;
801 if (fillattr != 0xFF)
802 ms->fillattr = fillattr;
803 if (spacechar != 0xFF)
804 ms->spacechar = spacechar;
805 if (shadowattr != 0xFF)
806 ms->shadowattr = shadowattr;
807}
808
809void set_menu_options(uchar maxmenuheight)
810{
811 if (maxmenuheight != 0xFF)
812 ms->maxmenuheight = maxmenuheight;
813}
814
815
816void set_window_size(uchar top, uchar left, uchar bot, uchar right)
817{
818 int nr, nc;
819
820 if ((top > bot) || (left > right))
821 return;
822
823 if (getscreensize(1, &nr, &nc)) {
824
825 nr = 80;
826 nc = 24;
827 }
828 if (bot >= nr)
829 bot = nr - 1;
830 if (right >= nc)
831 right = nc - 1;
832 ms->minrow = top;
833 ms->mincol = left;
834 ms->maxrow = bot;
835 ms->maxcol = right;
836 ms->numcols = right - left + 1;
837 ms->numrows = bot - top + 1;
838 if (ms->statline >= ms->numrows)
839 ms->statline = ms->numrows - 1;
840}
841
842void reg_handler(t_handler htype, void *handler)
843{
844
845 switch (htype) {
846 case HDLR_KEYS:
847 ms->keys_handler = (t_keys_handler) handler;
848 break;
849 default:
850 ms->handler = (t_menusystem_handler) handler;
851 break;
852 }
853}
854
855void unreg_handler(t_handler htype)
856{
857 switch (htype) {
858 case HDLR_KEYS:
859 ms->keys_handler = NULL;
860 break;
861 default:
862 ms->handler = NULL;
863 break;
864 }
865}
866
867void reg_ontimeout(t_timeout_handler handler, unsigned int numsteps,
868 unsigned int stepsize)
869{
870 ms->ontimeout = handler;
871 if (numsteps != 0)
872 ms->tm_numsteps = numsteps;
873 if (stepsize != 0)
874 ms->tm_stepsize = stepsize;
875}
876
877void unreg_ontimeout(void)
878{
879 ms->ontimeout = NULL;
880}
881
882void reg_ontotaltimeout(t_timeout_handler handler,
883 unsigned long numcentiseconds)
884{
885 if (numcentiseconds != 0) {
886 ms->ontotaltimeout = handler;
887 ms->tm_total_timeout = numcentiseconds * 10;
888 ms->tm_sofar_timeout = 0;
889 }
890}
891
892void unreg_ontotaltimeout(void)
893{
894 ms->ontotaltimeout = NULL;
895}
896
897int next_visible(pt_menu menu, int index)
898{
899 int ans;
900 if (index < 0)
901 ans = 0;
902 else if (index >= menu->numitems)
903 ans = menu->numitems - 1;
904 else
905 ans = index;
906 while ((ans < menu->numitems - 1) &&
907 ((menu->items[ans]->action == OPT_INVISIBLE) ||
908 (menu->items[ans]->action == OPT_SEP)))
909 ans++;
910 return ans;
911}
912
913int prev_visible(pt_menu menu, int index)
914{
915 int ans;
916 if (index < 0)
917 ans = 0;
918 else if (index >= menu->numitems)
919 ans = menu->numitems - 1;
920 else
921 ans = index;
922 while ((ans > 0) &&
923 ((menu->items[ans]->action == OPT_INVISIBLE) ||
924 (menu->items[ans]->action == OPT_SEP)))
925 ans--;
926 return ans;
927}
928
929int next_visible_sep(pt_menu menu, int index)
930{
931 int ans;
932 if (index < 0)
933 ans = 0;
934 else if (index >= menu->numitems)
935 ans = menu->numitems - 1;
936 else
937 ans = index;
938 while ((ans < menu->numitems - 1) &&
939 (menu->items[ans]->action == OPT_INVISIBLE))
940 ans++;
941 return ans;
942}
943
944int prev_visible_sep(pt_menu menu, int index)
945{
946 int ans;
947 if (index < 0)
948 ans = 0;
949 else if (index >= menu->numitems)
950 ans = menu->numitems - 1;
951 else
952 ans = index;
953 while ((ans > 0) && (menu->items[ans]->action == OPT_INVISIBLE))
954 ans--;
955 return ans;
956}
957
958int calc_visible(pt_menu menu, int first)
959{
960 int ans, i;
961
962 if (menu == NULL)
963 return 0;
964 ans = 0;
965 for (i = first; i < menu->numitems; i++)
966 if (menu->items[i]->action != OPT_INVISIBLE)
967 ans++;
968 return ans;
969}
970
971
972int isvisible(pt_menu menu, int first, int curr)
973{
974 if (curr < first)
975 return 0;
976 return (calc_visible(menu, first) - calc_visible(menu, curr) <
977 menu->menuheight);
978}
979
980
981
982int calc_first_late(pt_menu menu, int curr)
983{
984 int ans, i, nv;
985
986 nv = calc_visible(menu, 0);
987 if (nv <= menu->menuheight)
988 return 0;
989
990 ans = curr + 1;
991 for (i = 0; i < menu->menuheight; i++)
992 ans = prev_visible_sep(menu, ans - 1);
993 return ans;
994}
995
996
997
998int calc_first_early(pt_menu menu, int curr)
999{
1000 int ans, i, nv;
1001
1002 nv = calc_visible(menu, 0);
1003 if (nv <= menu->menuheight)
1004 return 0;
1005
1006
1007 nv = calc_visible(menu, curr);
1008 ans = curr;
1009 for (i = 0; i < menu->menuheight - nv; i++)
1010 ans = prev_visible_sep(menu, ans - 1);
1011 return ans;
1012}
1013
1014
1015uchar add_menu(const char *title, int maxmenusize)
1016{
1017 int num, i;
1018 pt_menu m;
1019
1020 num = ms->nummenus;
1021 if (num >= MAXMENUS)
1022 return -1;
1023 m = NULL;
1024 m = (pt_menu) malloc(sizeof(t_menu));
1025 if (m == NULL)
1026 return -1;
1027 ms->menus[num] = m;
1028 m->numitems = 0;
1029 m->name = NULL;
1030 m->row = 0xFF;
1031 m->col = 0xFF;
1032 if (maxmenusize < 1)
1033 m->maxmenusize = MAXMENUSIZE;
1034 else
1035 m->maxmenusize = maxmenusize;
1036 m->items = (pt_menuitem *) malloc(sizeof(pt_menuitem) * (m->maxmenusize));
1037 for (i = 0; i < m->maxmenusize; i++)
1038 m->items[i] = NULL;
1039
1040 m->title = (char *)malloc(MENULEN + 1);
1041 if (title) {
1042 if (strlen(title) > MENULEN - 2)
1043 strcpy(m->title, TITLELONG);
1044 else
1045 strcpy(m->title, title);
1046 } else
1047 strcpy(m->title, EMPTYSTR);
1048 m->menuwidth = strlen(m->title);
1049 ms->nummenus++;
1050 return ms->nummenus - 1;
1051}
1052
1053void set_menu_name(const char *name)
1054{
1055 pt_menu m;
1056
1057 m = ms->menus[ms->nummenus - 1];
1058 if (m->name)
1059 {
1060 free(m->name);
1061 m->name = NULL;
1062 }
1063
1064 if (name) {
1065 m->name = (char *)malloc(strlen(name) + 1);
1066 strcpy(m->name, name);
1067 }
1068}
1069
1070
1071uchar add_named_menu(const char *name, const char *title, int maxmenusize)
1072{
1073 add_menu(title, maxmenusize);
1074 set_menu_name(name);
1075 return ms->nummenus - 1;
1076}
1077
1078void set_menu_pos(uchar row, uchar col)
1079{
1080 pt_menu m;
1081
1082 m = ms->menus[ms->nummenus - 1];
1083 m->row = row;
1084 m->col = col;
1085}
1086
1087pt_menuitem add_sep(void)
1088{
1089 pt_menuitem mi;
1090 pt_menu m;
1091
1092 m = (ms->menus[ms->nummenus - 1]);
1093 mi = NULL;
1094 mi = (pt_menuitem) malloc(sizeof(t_menuitem));
1095 if (mi == NULL)
1096 return NULL;
1097 m->items[(unsigned int)m->numitems] = mi;
1098 mi->handler = NULL;
1099 mi->item = mi->status = mi->data = NULL;
1100 mi->action = OPT_SEP;
1101 mi->index = m->numitems++;
1102 mi->parindex = ms->nummenus - 1;
1103 mi->shortcut = 0;
1104 mi->helpid = 0;
1105 return mi;
1106}
1107
1108
1109pt_menuitem add_item(const char *item, const char *status, t_action action,
1110 const char *data, uchar itemdata)
1111{
1112 pt_menuitem mi;
1113 pt_menu m;
1114 const char *str;
1115 uchar inhlite = 0;
1116
1117 m = (ms->menus[ms->nummenus - 1]);
1118 mi = NULL;
1119 mi = (pt_menuitem) malloc(sizeof(t_menuitem));
1120 if (mi == NULL)
1121 return NULL;
1122 m->items[(unsigned int)m->numitems] = mi;
1123 mi->handler = NULL;
1124
1125
1126 mi->item = (char *)malloc(MENULEN + 1);
1127 mi->status = (char *)malloc(STATLEN + 1);
1128 mi->data = (char *)malloc(ACTIONLEN + 1);
1129
1130 if (item) {
1131 if (strlen(item) > MENULEN) {
1132 strcpy(mi->item, ITEMLONG);
1133 } else {
1134 strcpy(mi->item, item);
1135 }
1136 if (strlen(mi->item) > m->menuwidth)
1137 m->menuwidth = strlen(mi->item);
1138 } else
1139 strcpy(mi->item, EMPTYSTR);
1140
1141 if (status) {
1142 if (strlen(status) > STATLEN) {
1143 strcpy(mi->status, STATUSLONG);
1144 } else {
1145 strcpy(mi->status, status);
1146 }
1147 } else
1148 strcpy(mi->status, EMPTYSTR);
1149
1150 mi->action = action;
1151 str = mi->item;
1152 mi->shortcut = 0;
1153 mi->helpid = 0xFFFF;
1154 inhlite = 0;
1155
1156 while (*str) {
1157 if (*str == ENABLEHLITE) {
1158 inhlite = 1;
1159 }
1160 if (*str == DISABLEHLITE) {
1161 inhlite = 0;
1162 }
1163 if ((inhlite == 1) &&
1164 (((*str >= 'A') && (*str <= 'Z')) ||
1165 ((*str >= 'a') && (*str <= 'z')) ||
1166 ((*str >= '0') && (*str <= '9')))) {
1167 mi->shortcut = *str;
1168 break;
1169 }
1170 ++str;
1171 }
1172 if ((mi->shortcut >= 'A') && (mi->shortcut <= 'Z'))
1173 mi->shortcut = mi->shortcut - 'A' + 'a';
1174
1175 if (data) {
1176 if (strlen(data) > ACTIONLEN) {
1177 strcpy(mi->data, ACTIONLONG);
1178 } else {
1179 strcpy(mi->data, data);
1180 }
1181 } else
1182 strcpy(mi->data, EMPTYSTR);
1183
1184 switch (action) {
1185 case OPT_SUBMENU:
1186 mi->itemdata.submenunum = itemdata;
1187 break;
1188 case OPT_CHECKBOX:
1189 mi->itemdata.checked = itemdata;
1190 break;
1191 case OPT_RADIOMENU:
1192 mi->itemdata.radiomenunum = itemdata;
1193 if (mi->data)
1194 free(mi->data);
1195 mi->data = NULL;
1196 break;
1197 default:
1198 break;
1199 }
1200 mi->index = m->numitems++;
1201 mi->parindex = ms->nummenus - 1;
1202 return mi;
1203}
1204
1205
1206void set_item_options(uchar shortcut, int helpid)
1207{
1208 pt_menuitem mi;
1209 pt_menu m;
1210
1211 m = (ms->menus[ms->nummenus - 1]);
1212 if (m->numitems <= 0)
1213 return;
1214 mi = m->items[(unsigned int)m->numitems - 1];
1215
1216 if (shortcut != 0xFF)
1217 mi->shortcut = shortcut;
1218 if (helpid != 0xFFFF)
1219 mi->helpid = helpid;
1220}
1221
1222
1223void close_menusystem(void)
1224{
1225}
1226
1227
1228void append_line_helper(int menunum, char *line)
1229{
1230 pt_menu menu;
1231 pt_menuitem mi, ri;
1232 char *app;
1233 int ctr;
1234
1235 menu = ms->menus[menunum];
1236 for (ctr = 0; ctr < (int)menu->numitems; ctr++) {
1237 mi = menu->items[ctr];
1238 app = NULL;
1239 switch (mi->action) {
1240 case OPT_CHECKBOX:
1241 if (mi->itemdata.checked)
1242 app = mi->data;
1243 break;
1244 case OPT_RADIOMENU:
1245 if (mi->data) {
1246 ri = (pt_menuitem) (mi->data);
1247 app = ri->data;
1248 }
1249 break;
1250 case OPT_SUBMENU:
1251 append_line_helper(mi->itemdata.submenunum, line);
1252 break;
1253 default:
1254 break;
1255 }
1256 if (app) {
1257 strcat(line, " ");
1258 strcat(line, app);
1259 }
1260 }
1261}
1262
1263
1264
1265void gen_append_line(const char *menu_name, char *line)
1266{
1267 int menunum;
1268
1269 menunum = find_menu_num(menu_name);
1270 if (menunum < 0)
1271 return;
1272 append_line_helper(menunum, line);
1273}
1274