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