Rocco Rutte:
[apps/madmutt.git] / menu.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include "mutt.h"
15 #include "mutt_curses.h"
16 #include "mutt_menu.h"
17 #include "mbyte.h"
18 #include "sidebar.h"
19
20 #ifdef USE_IMAP
21 #include "imap.h"
22 #endif
23
24 #include <string.h>
25 #include <stdlib.h>
26
27 extern int Charset_is_utf8;     /* FIXME: bad modularisation */
28
29 extern size_t UngetCount;
30
31 static void print_enriched_string (int attr, unsigned char *s, int do_color)
32 {
33   wchar_t wc;
34   size_t k;
35   size_t n = mutt_strlen ((char *) s);
36   mbstate_t mbstate;
37
38   memset (&mbstate, 0, sizeof (mbstate));
39   while (*s) {
40     if (*s < M_TREE_MAX) {
41       if (do_color)
42         SETCOLOR (MT_COLOR_TREE);
43       while (*s && *s < M_TREE_MAX) {
44         switch (*s) {
45         case M_TREE_LLCORNER:
46           if (option (OPTASCIICHARS))
47             addch ('`');
48           else if (Charset_is_utf8)
49             addstr ("\342\224\224");    /* WACS_LLCORNER */
50           else
51             addch (ACS_LLCORNER);
52           break;
53         case M_TREE_ULCORNER:
54           if (option (OPTASCIICHARS))
55             addch (',');
56           else if (Charset_is_utf8)
57             addstr ("\342\224\214");    /* WACS_ULCORNER */
58           else
59             addch (ACS_ULCORNER);
60           break;
61         case M_TREE_LTEE:
62           if (option (OPTASCIICHARS))
63             addch ('|');
64           else if (Charset_is_utf8)
65             addstr ("\342\224\234");    /* WACS_LTEE */
66           else
67             addch (ACS_LTEE);
68           break;
69         case M_TREE_HLINE:
70           if (option (OPTASCIICHARS))
71             addch ('-');
72           else if (Charset_is_utf8)
73             addstr ("\342\224\200");    /* WACS_HLINE */
74           else
75             addch (ACS_HLINE);
76           break;
77         case M_TREE_VLINE:
78           if (option (OPTASCIICHARS))
79             addch ('|');
80           else if (Charset_is_utf8)
81             addstr ("\342\224\202");    /* WACS_VLINE */
82           else
83             addch (ACS_VLINE);
84           break;
85         case M_TREE_TTEE:
86           if (option (OPTASCIICHARS))
87             addch ('-');
88           else if (Charset_is_utf8)
89             addstr ("\342\224\254");    /* WACS_TTEE */
90           else
91             addch (ACS_TTEE);
92           break;
93         case M_TREE_BTEE:
94           if (option (OPTASCIICHARS))
95             addch ('-');
96           else if (Charset_is_utf8)
97             addstr ("\342\224\264");    /* WACS_BTEE */
98           else
99             addch (ACS_BTEE);
100           break;
101         case M_TREE_SPACE:
102           addch (' ');
103           break;
104         case M_TREE_RARROW:
105           addch ('>');
106           break;
107         case M_TREE_STAR:
108           addch ('*');          /* fake thread indicator */
109           break;
110         case M_TREE_HIDDEN:
111           addch ('&');
112           break;
113         case M_TREE_EQUALS:
114           addch ('=');
115           break;
116         case M_TREE_MISSING:
117           addch ('?');
118           break;
119         }
120         s++, n--;
121       }
122       if (do_color)
123         attrset (attr);
124     }
125     else if ((k = mbrtowc (&wc, (char *) s, n, &mbstate)) > 0) {
126       addnstr ((char *) s, k);
127       s += k, n -= k;
128     }
129     else
130       break;
131   }
132 }
133
134 static void menu_make_entry (char *s, int l, MUTTMENU * menu, int i)
135 {
136   if (menu->dialog) {
137     strncpy (s, menu->dialog[i], l);
138     menu->current = -1;         /* hide menubar */
139   }
140   else
141     menu->make_entry (s, l, menu, i);
142 }
143
144 void menu_pad_string (char *s, size_t n)
145 {
146   int shift = option (OPTARROWCURSOR) ? 3 : 0;
147   int cols;
148   char *tmpbuf = safe_malloc (n);
149
150   if (option (OPTMBOXPANE))
151     cols = COLS - shift - SidebarWidth;
152   else
153     cols = COLS - shift;
154   mutt_format_string (tmpbuf, n, cols, cols, 0, ' ', s, strlen (s), 1);
155   tmpbuf[n - 1] = 0;
156   snprintf (s, n, "%s", tmpbuf);        /* overkill */
157   FREE (&tmpbuf);
158 }
159
160 void menu_redraw_full (MUTTMENU * menu)
161 {
162   SETCOLOR (MT_COLOR_NORMAL);
163   /* clear() doesn't optimize screen redraws */
164   move (0, 0);
165   clrtobot ();
166
167   if (option (OPTHELP)) {
168     SETCOLOR (MT_COLOR_STATUS);
169     move (option (OPTSTATUSONTOP) ? LINES - 2 : 0, 0);
170     mutt_paddstr (COLS, menu->help);
171     SETCOLOR (MT_COLOR_NORMAL);
172     menu->offset = 1;
173     menu->pagelen = LINES - 3;
174   }
175   else {
176     menu->offset = option (OPTSTATUSONTOP) ? 1 : 0;
177     menu->pagelen = LINES - 2;
178   }
179
180   mutt_show_error ();
181
182   menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
183 }
184
185 void menu_redraw_status (MUTTMENU * menu)
186 {
187   char buf[STRING];
188
189   snprintf (buf, sizeof (buf), M_MODEFMT, menu->title);
190   SETCOLOR (MT_COLOR_STATUS);
191   move (option (OPTSTATUSONTOP) ? 0 : LINES - 2, 0);
192   mutt_paddstr (COLS, buf);
193   SETCOLOR (MT_COLOR_NORMAL);
194   menu->redraw &= ~REDRAW_STATUS;
195 }
196
197 void menu_redraw_index (MUTTMENU * menu)
198 {
199   char buf[STRING];
200   int i;
201
202   draw_sidebar (1);
203   for (i = menu->top; i < menu->top + menu->pagelen; i++) {
204     if (i < menu->max) {
205       menu_make_entry (buf, sizeof (buf), menu, i);
206       menu_pad_string (buf, sizeof (buf));
207
208       if (option (OPTARROWCURSOR)) {
209         attrset (menu->color (i));
210         CLEARLINE_WIN (i - menu->top + menu->offset);
211
212         if (i == menu->current) {
213           attrset (menu->color (i));
214           ADDCOLOR (MT_COLOR_INDICATOR);
215           addstr ("->");
216           attrset (menu->color (i));
217           addch (' ');
218         }
219         else
220           move (i - menu->top + menu->offset, SidebarWidth + 3);
221
222         print_enriched_string (menu->color (i), (unsigned char *) buf, 1);
223         SETCOLOR (MT_COLOR_NORMAL);
224       }
225       else {
226         attrset (menu->color (i));
227
228         if (i == menu->current) {
229           ADDCOLOR (MT_COLOR_INDICATOR);
230           BKGDSET (MT_COLOR_INDICATOR);
231         }
232
233         CLEARLINE_WIN (i - menu->top + menu->offset);
234         print_enriched_string (menu->color (i), (unsigned char *) buf,
235                                i != menu->current);
236         SETCOLOR (MT_COLOR_NORMAL);
237         BKGDSET (MT_COLOR_NORMAL);
238       }
239     }
240     else
241       CLEARLINE_WIN (i - menu->top + menu->offset);
242   }
243   menu->redraw = 0;
244 }
245
246 void menu_redraw_motion (MUTTMENU * menu)
247 {
248   char buf[STRING];
249
250   if (menu->dialog) {
251     menu->redraw &= ~REDRAW_MOTION;
252     return;
253   }
254
255   move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth);
256   SETCOLOR (MT_COLOR_NORMAL);
257   BKGDSET (MT_COLOR_NORMAL);
258
259   if (option (OPTARROWCURSOR)) {
260     /* clear the pointer */
261     attrset (menu->color (menu->oldcurrent));
262     addstr ("  ");
263
264     if (menu->redraw & REDRAW_MOTION_RESYNCH) {
265       clrtoeol ();
266       menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
267       menu_pad_string (buf, sizeof (buf));
268       move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth + 3);
269       print_enriched_string (menu->color (menu->oldcurrent),
270                              (unsigned char *) buf, 1);
271       SETCOLOR (MT_COLOR_NORMAL);
272     }
273
274     /* now draw it in the new location */
275     move (menu->current + menu->offset - menu->top, SidebarWidth);
276     attrset (menu->color (menu->current));
277     ADDCOLOR (MT_COLOR_INDICATOR);
278     addstr ("->");
279     SETCOLOR (MT_COLOR_NORMAL);
280   }
281   else {
282     /* erase the current indicator */
283     attrset (menu->color (menu->oldcurrent));
284     clrtoeol ();
285     menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
286     menu_pad_string (buf, sizeof (buf));
287     print_enriched_string (menu->color (menu->oldcurrent),
288                            (unsigned char *) buf, 1);
289
290     /* now draw the new one to reflect the change */
291     menu_make_entry (buf, sizeof (buf), menu, menu->current);
292     menu_pad_string (buf, sizeof (buf));
293     attrset (menu->color (menu->current));
294     ADDCOLOR (MT_COLOR_INDICATOR);
295     BKGDSET (MT_COLOR_INDICATOR);
296     CLEARLINE_WIN (menu->current - menu->top + menu->offset);
297     print_enriched_string (menu->color (menu->current), (unsigned char *) buf,
298                            0);
299     SETCOLOR (MT_COLOR_NORMAL);
300     BKGDSET (MT_COLOR_NORMAL);
301   }
302   menu->redraw &= REDRAW_STATUS;
303 }
304
305 void menu_redraw_current (MUTTMENU * menu)
306 {
307   char buf[STRING];
308
309   move (menu->current + menu->offset - menu->top, SidebarWidth);
310   menu_make_entry (buf, sizeof (buf), menu, menu->current);
311   menu_pad_string (buf, sizeof (buf));
312
313   if (option (OPTARROWCURSOR)) {
314     int attr = menu->color (menu->current);
315
316     attrset (attr);
317     clrtoeol ();
318     attrset (menu->color (menu->current));
319     ADDCOLOR (MT_COLOR_INDICATOR);
320     addstr ("->");
321     attrset (attr);
322     addch (' ');
323     menu_pad_string (buf, sizeof (buf));
324     print_enriched_string (menu->color (menu->current), (unsigned char *) buf,
325                            1);
326     SETCOLOR (MT_COLOR_NORMAL);
327   }
328   else {
329     attrset (menu->color (menu->current));
330     ADDCOLOR (MT_COLOR_INDICATOR);
331     BKGDSET (MT_COLOR_INDICATOR);
332     clrtoeol ();
333     print_enriched_string (menu->color (menu->current), (unsigned char *) buf,
334                            0);
335     SETCOLOR (MT_COLOR_NORMAL);
336     BKGDSET (MT_COLOR_NORMAL);
337   }
338   menu->redraw &= REDRAW_STATUS;
339 }
340
341 void menu_redraw_prompt (MUTTMENU * menu)
342 {
343   if (menu->dialog) {
344     if (option (OPTMSGERR)) {
345       mutt_sleep (1);
346       unset_option (OPTMSGERR);
347     }
348
349     if (*Errorbuf)
350       mutt_clear_error ();
351
352     SETCOLOR (MT_COLOR_NORMAL);
353     mvaddstr (LINES - 1, 0, menu->prompt);
354     clrtoeol ();
355   }
356 }
357
358 void menu_check_recenter (MUTTMENU * menu)
359 {
360   int c = MIN (MenuContext, menu->pagelen / 2);
361   int old_top = menu->top;
362
363   if (!option (OPTMENUMOVEOFF) && menu->max <= menu->pagelen) { /* less entries than lines */
364     if (menu->top != 0) {
365       menu->top = 0;
366       set_option (OPTNEEDREDRAW);
367     }
368   }
369   else if (menu->current >= menu->top + menu->pagelen - c) {    /* indicator below bottom threshold */
370     if (option (OPTMENUSCROLL) || (menu->pagelen <= 0))
371       menu->top = menu->current - menu->pagelen + c + 1;
372     else
373       menu->top +=
374         (menu->pagelen -
375          c) * ((menu->current - menu->top) / (menu->pagelen - c)) - c;
376   }
377   else if (menu->current < menu->top + c) {     /* indicator above top threshold */
378     if (option (OPTMENUSCROLL) || (menu->pagelen <= 0))
379       menu->top = menu->current - c;
380     else
381       menu->top -=
382         (menu->pagelen -
383          c) * ((menu->top + menu->pagelen - 1 -
384                 menu->current) / (menu->pagelen - c)) - c;
385   }
386
387   if (!option (OPTMENUMOVEOFF)) /* make entries stick to bottom */
388     menu->top = MIN (menu->top, menu->max - menu->pagelen);
389   menu->top = MAX (menu->top, 0);
390
391   if (menu->top != old_top)
392     menu->redraw |= REDRAW_INDEX;
393 }
394
395 void menu_jump (MUTTMENU * menu)
396 {
397   int n;
398   char buf[SHORT_STRING];
399
400   if (menu->max) {
401     mutt_ungetch (LastKey, 0);
402     buf[0] = 0;
403     if (mutt_get_field (_("Jump to: "), buf, sizeof (buf), 0) == 0 && buf[0]) {
404       n = atoi (buf) - 1;
405       if (n >= 0 && n < menu->max) {
406         menu->current = n;
407         menu->redraw = REDRAW_MOTION;
408       }
409       else
410         mutt_error _("Invalid index number.");
411     }
412   }
413   else
414     mutt_error _("No entries.");
415 }
416
417 void menu_next_line (MUTTMENU * menu)
418 {
419   if (menu->max) {
420     int c = MIN (MenuContext, menu->pagelen / 2);
421
422     if (menu->top + 1 < menu->max - c && (option (OPTMENUMOVEOFF)
423                                           || (menu->max > menu->pagelen
424                                               && menu->top <
425                                               menu->max - menu->pagelen))) {
426       menu->top++;
427       if (menu->current < menu->top + c && menu->current < menu->max - 1)
428         menu->current++;
429       menu->redraw = REDRAW_INDEX;
430     }
431     else
432       mutt_error _("You cannot scroll down farther.");
433   }
434   else
435     mutt_error _("No entries.");
436 }
437
438 void menu_prev_line (MUTTMENU * menu)
439 {
440   if (menu->top > 0) {
441     int c = MIN (MenuContext, menu->pagelen / 2);
442
443     menu->top--;
444     if (menu->current >= menu->top + menu->pagelen - c && menu->current > 1)
445       menu->current--;
446     menu->redraw = REDRAW_INDEX;
447   }
448   else
449     mutt_error _("You cannot scroll up farther.");
450 }
451
452 void menu_next_page (MUTTMENU * menu)
453 {
454   if (menu->max) {
455     if (menu->top + menu->pagelen < menu->max) {
456       menu->top += menu->pagelen;
457       if (menu->current < menu->top)
458         menu->current = menu->top;
459       menu->redraw = REDRAW_INDEX;
460     }
461     else if (menu->current != menu->max - 1 && !menu->dialog) {
462       menu->current = menu->max - 1;
463       menu->redraw = REDRAW_MOTION;
464     }
465     else
466       mutt_error _("You are on the last page.");
467   }
468   else
469     mutt_error _("No entries.");
470 }
471
472 void menu_prev_page (MUTTMENU * menu)
473 {
474   int c = MIN (MenuContext, menu->pagelen / 2);
475
476   if (menu->top > c) {
477     if ((menu->top -= menu->pagelen) < 0)
478       menu->top = 0;
479     if (menu->current >= menu->top + menu->pagelen)
480       menu->current = menu->top + menu->pagelen - 1;
481     menu->redraw = REDRAW_INDEX;
482   }
483   else if (menu->current && !menu->dialog) {
484     menu->current = 0;
485     menu->redraw = REDRAW_MOTION;
486   }
487   else
488     mutt_error _("You are on the first page.");
489 }
490
491 void menu_top_page (MUTTMENU * menu)
492 {
493   if (menu->current != menu->top) {
494     menu->current = menu->top;
495     menu->redraw = REDRAW_MOTION;
496   }
497 }
498
499 void menu_bottom_page (MUTTMENU * menu)
500 {
501   if (menu->max) {
502     menu->current = menu->top + menu->pagelen - 1;
503     if (menu->current > menu->max - 1)
504       menu->current = menu->max - 1;
505     menu->redraw = REDRAW_MOTION;
506   }
507   else
508     mutt_error _("No entries.");
509 }
510
511 void menu_middle_page (MUTTMENU * menu)
512 {
513   int i;
514
515   if (menu->max) {
516     i = menu->top + menu->pagelen;
517     if (i > menu->max - 1)
518       i = menu->max - 1;
519     menu->current = menu->top + (i - menu->top) / 2;
520     menu->redraw = REDRAW_MOTION;
521   }
522   else
523     mutt_error _("No entries.");
524 }
525
526 void menu_first_entry (MUTTMENU * menu)
527 {
528   if (menu->max) {
529     menu->current = 0;
530     menu->redraw = REDRAW_MOTION;
531   }
532   else
533     mutt_error _("No entries.");
534 }
535
536 void menu_last_entry (MUTTMENU * menu)
537 {
538   if (menu->max) {
539     menu->current = menu->max - 1;
540     menu->redraw = REDRAW_MOTION;
541   }
542   else
543     mutt_error _("No entries.");
544 }
545
546 void menu_half_up (MUTTMENU * menu)
547 {
548   if (menu->top > 0) {
549     if ((menu->top -= menu->pagelen / 2) < 0)
550       menu->top = 0;
551     if (menu->current >= menu->top + menu->pagelen)
552       menu->current = menu->top + menu->pagelen - 1;
553     menu->redraw = REDRAW_INDEX;
554   }
555   else if (menu->current && !menu->dialog) {
556     menu->current = 0;
557     menu->redraw = REDRAW_MOTION;
558   }
559   else
560     mutt_error _("First entry is shown.");
561 }
562
563 void menu_half_down (MUTTMENU * menu)
564 {
565   if (menu->max) {
566     if (menu->top + menu->pagelen < menu->max) {
567       menu->top += menu->pagelen / 2;
568       if (menu->current < menu->top)
569         menu->current = menu->top;
570       menu->redraw = REDRAW_INDEX;
571     }
572     else if (menu->current != menu->max - 1 && !menu->dialog) {
573       menu->current = menu->max - 1;
574       menu->redraw = REDRAW_INDEX;
575     }
576     else
577       mutt_error _("Last entry is shown.");
578   }
579   else
580     mutt_error _("No entries.");
581 }
582
583 void menu_current_top (MUTTMENU * menu)
584 {
585   if (menu->max) {
586     menu->top = menu->current;
587     menu->redraw = REDRAW_INDEX;
588   }
589   else
590     mutt_error _("No entries.");
591 }
592
593 void menu_current_middle (MUTTMENU * menu)
594 {
595   if (menu->max) {
596     menu->top = menu->current - menu->pagelen / 2;
597     if (menu->top < 0)
598       menu->top = 0;
599     menu->redraw = REDRAW_INDEX;
600   }
601   else
602     mutt_error _("No entries.");
603 }
604
605 void menu_current_bottom (MUTTMENU * menu)
606 {
607   if (menu->max) {
608     menu->top = menu->current - menu->pagelen + 1;
609     if (menu->top < 0)
610       menu->top = 0;
611     menu->redraw = REDRAW_INDEX;
612   }
613   else
614     mutt_error _("No entries.");
615 }
616
617 void menu_next_entry (MUTTMENU * menu)
618 {
619   if (menu->current < menu->max - 1) {
620     menu->current++;
621     menu->redraw = REDRAW_MOTION;
622   }
623   else
624     mutt_error _("You are on the last entry.");
625 }
626
627 void menu_prev_entry (MUTTMENU * menu)
628 {
629   if (menu->current) {
630     menu->current--;
631     menu->redraw = REDRAW_MOTION;
632   }
633   else
634     mutt_error _("You are on the first entry.");
635 }
636
637 static int default_color (int i)
638 {
639   return ColorDefs[MT_COLOR_NORMAL];
640 }
641
642 static int menu_search_generic (MUTTMENU * m, regex_t * re, int n)
643 {
644   char buf[LONG_STRING];
645
646   menu_make_entry (buf, sizeof (buf), m, n);
647   return (regexec (re, buf, 0, NULL, 0));
648 }
649
650 MUTTMENU *mutt_new_menu (void)
651 {
652   MUTTMENU *p = (MUTTMENU *) safe_calloc (1, sizeof (MUTTMENU));
653
654   p->current = 0;
655   p->top = 0;
656   p->offset = 1;
657   p->redraw = REDRAW_FULL;
658   p->pagelen = PAGELEN;
659   p->color = default_color;
660   p->search = menu_search_generic;
661   return (p);
662 }
663
664 void mutt_menuDestroy (MUTTMENU ** p)
665 {
666   int i;
667
668   FREE (&(*p)->searchBuf);
669
670   if ((*p)->dialog) {
671     for (i = 0; i < (*p)->max; i++)
672       FREE (&(*p)->dialog[i]);
673
674     FREE (&(*p)->dialog);
675   }
676
677   FREE (p);
678 }
679
680 #define M_SEARCH_UP   1
681 #define M_SEARCH_DOWN 2
682
683 static int menu_search (MUTTMENU * menu, int op)
684 {
685   int r;
686   int searchDir;
687   regex_t re;
688   char buf[SHORT_STRING];
689
690   if (op != OP_SEARCH_NEXT && op != OP_SEARCH_OPPOSITE) {
691     strfcpy (buf, menu->searchBuf ? menu->searchBuf : "", sizeof (buf));
692     if (mutt_get_field ((op == OP_SEARCH) ? _("Search for: ") :
693                         _("Reverse search for: "),
694                         buf, sizeof (buf), M_CLEAR) != 0 || !buf[0])
695       return (-1);
696     mutt_str_replace (&menu->searchBuf, buf);
697     menu->searchDir = (op == OP_SEARCH) ? M_SEARCH_DOWN : M_SEARCH_UP;
698   }
699   else {
700     if (!menu->searchBuf) {
701       mutt_error _("No search pattern.");
702
703       return (-1);
704     }
705   }
706
707   searchDir = (menu->searchDir == M_SEARCH_UP) ? -1 : 1;
708   if (op == OP_SEARCH_OPPOSITE)
709     searchDir = -searchDir;
710
711   if ((r =
712        REGCOMP (&re, menu->searchBuf,
713                 REG_NOSUB | mutt_which_case (menu->searchBuf))) != 0) {
714     regerror (r, &re, buf, sizeof (buf));
715     regfree (&re);
716     mutt_error ("%s", buf);
717     return (-1);
718   }
719
720   r = menu->current + searchDir;
721   while (r >= 0 && r < menu->max) {
722     if (menu->search (menu, &re, r) == 0) {
723       regfree (&re);
724       return r;
725     }
726
727     r += searchDir;
728   }
729
730   regfree (&re);
731   mutt_error _("Not found.");
732
733   return (-1);
734 }
735
736 static int menu_dialog_translate_op (int i)
737 {
738   switch (i) {
739   case OP_NEXT_ENTRY:
740     return OP_NEXT_LINE;
741   case OP_PREV_ENTRY:
742     return OP_PREV_LINE;
743   case OP_CURRENT_TOP:
744   case OP_FIRST_ENTRY:
745     return OP_TOP_PAGE;
746   case OP_CURRENT_BOTTOM:
747   case OP_LAST_ENTRY:
748     return OP_BOTTOM_PAGE;
749   case OP_CURRENT_MIDDLE:
750     return OP_MIDDLE_PAGE;
751   }
752
753   return i;
754 }
755
756 static int menu_dialog_dokey (MUTTMENU * menu, int *ip)
757 {
758   event_t ch;
759   char *p;
760
761   ch = mutt_getch ();
762
763   if (ch.ch == -1) {
764     *ip = -1;
765     return 0;
766   }
767
768   if (ch.ch && (p = strchr (menu->keys, ch.ch))) {
769     *ip = OP_MAX + (p - menu->keys + 1);
770     return 0;
771   }
772   else {
773     mutt_ungetch (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0);
774     return -1;
775   }
776 }
777
778 int menu_redraw (MUTTMENU * menu)
779 {
780   /* See if all or part of the screen needs to be updated.  */
781   if (menu->redraw & REDRAW_FULL) {
782     menu_redraw_full (menu);
783     /* allow the caller to do any local configuration */
784     return (OP_REDRAW);
785   }
786
787   if (!menu->dialog)
788     menu_check_recenter (menu);
789
790   if (menu->redraw & REDRAW_STATUS)
791     menu_redraw_status (menu);
792   if (menu->redraw & REDRAW_INDEX)
793     menu_redraw_index (menu);
794   else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNCH))
795     menu_redraw_motion (menu);
796   else if (menu->redraw == REDRAW_CURRENT)
797     menu_redraw_current (menu);
798
799   if (menu->dialog)
800     menu_redraw_prompt (menu);
801
802   return OP_NULL;
803 }
804
805 int mutt_menuLoop (MUTTMENU * menu)
806 {
807   int i = OP_NULL;
808
809   FOREVER {
810     if (option (OPTMENUCALLER)) {
811       unset_option (OPTMENUCALLER);
812       return OP_NULL;
813     }
814
815
816     mutt_curs_set (0);
817
818 #ifdef USE_IMAP
819     imap_keepalive ();
820 #endif
821
822     if (menu_redraw (menu) == OP_REDRAW)
823       return OP_REDRAW;
824
825     menu->oldcurrent = menu->current;
826
827
828     /* move the cursor out of the way */
829     move (menu->current - menu->top + menu->offset,
830           (option (OPTARROWCURSOR) ? 2 : COLS - 1));
831
832     mutt_refresh ();
833
834     /* try to catch dialog keys before ops */
835     if (menu->dialog && menu_dialog_dokey (menu, &i) == 0)
836       return i;
837
838     i = km_dokey (menu->menu);
839     if (i == OP_TAG_PREFIX || i == OP_TAG_PREFIX_COND) {
840       if (menu->tagged) {
841         mvaddstr (LINES - 1, 0, "Tag-");
842         clrtoeol ();
843         i = km_dokey (menu->menu);
844         menu->tagprefix = 1;
845         CLEARLINE (LINES - 1);
846       }
847       else if (i == OP_TAG_PREFIX) {
848         mutt_error _("No tagged entries.");
849
850         i = -1;
851       }
852       else {                    /* None tagged, OP_TAG_PREFIX_COND */
853
854         event_t tmp;
855
856         while (UngetCount > 0) {
857           tmp = mutt_getch ();
858           if (tmp.op == OP_END_COND)
859             break;
860         }
861         mutt_message _("Nothing to do.");
862
863         i = -1;
864       }
865     }
866     else if (menu->tagged && option (OPTAUTOTAG))
867       menu->tagprefix = 1;
868     else
869       menu->tagprefix = 0;
870
871     mutt_curs_set (1);
872
873 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
874     if (SigWinch) {
875       mutt_resize_screen ();
876       menu->redraw = REDRAW_FULL;
877       SigWinch = 0;
878       clearok (stdscr, TRUE);   /*force complete redraw */
879     }
880 #endif
881
882     if (i == -1)
883       continue;
884
885     if (!menu->dialog)
886       mutt_clear_error ();
887
888     /* Convert menubar movement to scrolling */
889     if (menu->dialog)
890       i = menu_dialog_translate_op (i);
891
892     switch (i) {
893     case OP_NEXT_ENTRY:
894       menu_next_entry (menu);
895       break;
896     case OP_PREV_ENTRY:
897       menu_prev_entry (menu);
898       break;
899     case OP_HALF_DOWN:
900       menu_half_down (menu);
901       break;
902     case OP_HALF_UP:
903       menu_half_up (menu);
904       break;
905     case OP_NEXT_PAGE:
906       menu_next_page (menu);
907       break;
908     case OP_PREV_PAGE:
909       menu_prev_page (menu);
910       break;
911     case OP_NEXT_LINE:
912       menu_next_line (menu);
913       break;
914     case OP_PREV_LINE:
915       menu_prev_line (menu);
916       break;
917     case OP_FIRST_ENTRY:
918       menu_first_entry (menu);
919       break;
920     case OP_LAST_ENTRY:
921       menu_last_entry (menu);
922       break;
923     case OP_TOP_PAGE:
924       menu_top_page (menu);
925       break;
926     case OP_MIDDLE_PAGE:
927       menu_middle_page (menu);
928       break;
929     case OP_BOTTOM_PAGE:
930       menu_bottom_page (menu);
931       break;
932     case OP_CURRENT_TOP:
933       menu_current_top (menu);
934       break;
935     case OP_CURRENT_MIDDLE:
936       menu_current_middle (menu);
937       break;
938     case OP_CURRENT_BOTTOM:
939       menu_current_bottom (menu);
940       break;
941     case OP_SEARCH:
942     case OP_SEARCH_REVERSE:
943     case OP_SEARCH_NEXT:
944     case OP_SEARCH_OPPOSITE:
945       if (menu->search && !menu->dialog) {      /* Searching dialogs won't work */
946         menu->oldcurrent = menu->current;
947         if ((menu->current = menu_search (menu, i)) != -1)
948           menu->redraw = REDRAW_MOTION;
949         else
950           menu->current = menu->oldcurrent;
951       }
952       else
953         mutt_error _("Search is not implemented for this menu.");
954       break;
955
956     case OP_JUMP:
957       if (menu->dialog)
958         mutt_error (_("Jumping is not implemented for dialogs."));
959
960       else
961         menu_jump (menu);
962       break;
963
964     case OP_ENTER_COMMAND:
965       CurrentMenu = menu->menu;
966       mutt_enter_command ();
967       if (option (OPTFORCEREDRAWINDEX)) {
968         menu->redraw = REDRAW_FULL;
969         unset_option (OPTFORCEREDRAWINDEX);
970         unset_option (OPTFORCEREDRAWPAGER);
971       }
972       break;
973
974     case OP_TAG:
975       if (menu->tag && !menu->dialog) {
976         if (menu->tagprefix && !option (OPTAUTOTAG)) {
977           for (i = 0; i < menu->max; i++)
978             menu->tagged += menu->tag (menu, i, 0);
979           menu->redraw = REDRAW_INDEX;
980         }
981         else if (menu->max) {
982           int i = menu->tag (menu, menu->current, -1);
983
984           menu->tagged += i;
985           if (i && option (OPTRESOLVE) && menu->current < menu->max - 1) {
986             menu->current++;
987             menu->redraw = REDRAW_MOTION_RESYNCH;
988           }
989           else
990             menu->redraw = REDRAW_CURRENT;
991         }
992         else
993           mutt_error _("No entries.");
994       }
995       else
996         mutt_error _("Tagging is not supported.");
997       break;
998
999     case OP_SHELL_ESCAPE:
1000       mutt_shell_escape ();
1001       MAYBE_REDRAW (menu->redraw);
1002       break;
1003
1004     case OP_WHAT_KEY:
1005       mutt_what_key ();
1006       break;
1007
1008     case OP_REDRAW:
1009       clearok (stdscr, TRUE);
1010       menu->redraw = REDRAW_FULL;
1011       break;
1012
1013     case OP_HELP:
1014       mutt_help (menu->menu);
1015       menu->redraw = REDRAW_FULL;
1016       break;
1017
1018     case OP_NULL:
1019       km_error_key (menu->menu);
1020       break;
1021
1022     case OP_END_COND:
1023       break;
1024
1025     default:
1026       return (i);
1027     }
1028   }
1029   /* not reached */
1030 }