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