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