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