PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/menu.c

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