mutt stable branch with some hacks
at master 1102 lines 25 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 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}