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