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