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