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