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