NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
draw.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <stdbool.h>
31#include <stdio.h>
32#include <string.h>
33#include <wchar.h>
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "email/lib.h"
37#include "gui/lib.h"
38#include "color/lib.h"
39#include "index/lib.h"
40#include "menu/lib.h"
41#include "pattern/lib.h"
42#include "mutt_thread.h"
43#include "mview.h"
44#include "opcodes.h"
45
55static struct AttrColor *get_color(int index, unsigned char *s)
56{
57 const int type = *s;
58 struct RegexColorList *rcl = regex_colors_get_list(type);
59 if (rcl == NULL)
60 {
61 return simple_color_get(type);
62 }
63
64 struct RegexColor *np = NULL;
65 struct Mailbox *m_cur = get_current_mailbox();
66 struct Email *e = mutt_get_virt_email(m_cur, index);
67
68 if (type == MT_COLOR_INDEX_TAG)
69 {
70 struct AttrColor *ac_merge = NULL;
71 STAILQ_FOREACH(np, rcl, entries)
72 {
73 if (mutt_strn_equal((const char *) (s + 1), np->pattern, strlen(np->pattern)))
74 {
75 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
76 continue;
77 }
78 const char *transform = mutt_hash_find(TagTransforms, np->pattern);
79 if (transform && mutt_strn_equal((const char *) (s + 1), transform, strlen(transform)))
80 {
81 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
82 }
83 }
84 return ac_merge;
85 }
86
87 struct AttrColor *ac_merge = NULL;
88 STAILQ_FOREACH(np, rcl, entries)
89 {
91 MUTT_MATCH_FULL_ADDRESS, m_cur, e, NULL))
92 {
93 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
94 }
95 }
96
97 return ac_merge;
98}
99
109static void print_enriched_string(struct MuttWindow *win, int index,
110 struct AttrColor *ac_def, struct AttrColor *ac_ind,
111 unsigned char *s, struct ConfigSubset *sub)
112{
113 wchar_t wc = 0;
114 size_t k;
115 size_t n = mutt_str_len((char *) s);
116 mbstate_t mbstate = { 0 };
117
118 const bool c_ascii_chars = cs_subset_bool(sub, "ascii_chars");
119 while (*s)
120 {
121 if (*s < MUTT_TREE_MAX)
122 {
124 ac_merge = merged_color_overlay(ac_merge, ac_ind);
125
126 /* Combining tree fg color and another bg color requires having
127 * use_default_colors, because the other bg color may be undefined. */
128 mutt_curses_set_color(ac_merge);
129
130 while (*s && (*s < MUTT_TREE_MAX))
131 {
132 switch (*s)
133 {
135 if (c_ascii_chars)
136 mutt_window_addch(win, '`');
137#ifdef WACS_LLCORNER
138 else
139 add_wch(WACS_LLCORNER);
140#else
141 else if (CharsetIsUtf8)
142 mutt_window_addstr(win, "\342\224\224"); /* WACS_LLCORNER */
143 else
144 mutt_window_addch(win, ACS_LLCORNER);
145#endif
146 break;
148 if (c_ascii_chars)
149 mutt_window_addch(win, ',');
150#ifdef WACS_ULCORNER
151 else
152 add_wch(WACS_ULCORNER);
153#else
154 else if (CharsetIsUtf8)
155 mutt_window_addstr(win, "\342\224\214"); /* WACS_ULCORNER */
156 else
157 mutt_window_addch(win, ACS_ULCORNER);
158#endif
159 break;
160 case MUTT_TREE_LTEE:
161 if (c_ascii_chars)
162 mutt_window_addch(win, '|');
163#ifdef WACS_LTEE
164 else
165 add_wch(WACS_LTEE);
166#else
167 else if (CharsetIsUtf8)
168 mutt_window_addstr(win, "\342\224\234"); /* WACS_LTEE */
169 else
170 mutt_window_addch(win, ACS_LTEE);
171#endif
172 break;
173 case MUTT_TREE_HLINE:
174 if (c_ascii_chars)
175 mutt_window_addch(win, '-');
176#ifdef WACS_HLINE
177 else
178 add_wch(WACS_HLINE);
179#else
180 else if (CharsetIsUtf8)
181 mutt_window_addstr(win, "\342\224\200"); /* WACS_HLINE */
182 else
183 mutt_window_addch(win, ACS_HLINE);
184#endif
185 break;
186 case MUTT_TREE_VLINE:
187 if (c_ascii_chars)
188 mutt_window_addch(win, '|');
189#ifdef WACS_VLINE
190 else
191 add_wch(WACS_VLINE);
192#else
193 else if (CharsetIsUtf8)
194 mutt_window_addstr(win, "\342\224\202"); /* WACS_VLINE */
195 else
196 mutt_window_addch(win, ACS_VLINE);
197#endif
198 break;
199 case MUTT_TREE_TTEE:
200 if (c_ascii_chars)
201 mutt_window_addch(win, '-');
202#ifdef WACS_TTEE
203 else
204 add_wch(WACS_TTEE);
205#else
206 else if (CharsetIsUtf8)
207 mutt_window_addstr(win, "\342\224\254"); /* WACS_TTEE */
208 else
209 mutt_window_addch(win, ACS_TTEE);
210#endif
211 break;
212 case MUTT_TREE_BTEE:
213 if (c_ascii_chars)
214 mutt_window_addch(win, '-');
215#ifdef WACS_BTEE
216 else
217 add_wch(WACS_BTEE);
218#else
219 else if (CharsetIsUtf8)
220 mutt_window_addstr(win, "\342\224\264"); /* WACS_BTEE */
221 else
222 mutt_window_addch(win, ACS_BTEE);
223#endif
224 break;
225 case MUTT_TREE_SPACE:
226 mutt_window_addch(win, ' ');
227 break;
228 case MUTT_TREE_RARROW:
229 mutt_window_addch(win, '>');
230 break;
231 case MUTT_TREE_STAR:
232 mutt_window_addch(win, '*'); /* fake thread indicator */
233 break;
234 case MUTT_TREE_HIDDEN:
235 mutt_window_addch(win, '&');
236 break;
237 case MUTT_TREE_EQUALS:
238 mutt_window_addch(win, '=');
239 break;
241 mutt_window_addch(win, '?');
242 break;
243 }
244 s++;
245 n--;
246 }
247 ac_merge = merged_color_overlay(ac_def, ac_ind);
248 mutt_curses_set_color(ac_merge);
249 }
250 else if (*s == MUTT_SPECIAL_INDEX)
251 {
252 s++;
253 if (*s == MT_COLOR_INDEX)
254 {
255 struct AttrColor *ac_merge = merged_color_overlay(ac_def, ac_ind);
256 mutt_curses_set_color(ac_merge);
257 }
258 else
259 {
260 struct AttrColor *color = get_color(index, s);
261 struct AttrColor *ac_merge = merged_color_overlay(ac_def, color);
262 ac_merge = merged_color_overlay(ac_merge, ac_ind);
263
264 mutt_curses_set_color(ac_merge);
265 }
266 s++;
267 n -= 2;
268 }
269 else if ((k = mbrtowc(&wc, (char *) s, n, &mbstate)) > 0)
270 {
271 mutt_window_addnstr(win, (char *) s, k);
272 s += k;
273 n -= k;
274 }
275 else
276 break;
277 }
278}
279
288static void menu_pad_string(struct Menu *menu, char *buf, size_t buflen)
289{
290 char *scratch = mutt_str_dup(buf);
291 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
292 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
293 int shift = c_arrow_cursor ? mutt_strwidth(c_arrow_string) + 1 : 0;
294 int cols = menu->win->state.cols - shift;
295
296 mutt_simple_format(buf, buflen, cols, cols, JUSTIFY_LEFT, ' ', scratch,
297 mutt_str_len(scratch), true);
298 buf[buflen - 1] = '\0';
299 FREE(&scratch);
300}
301
306void menu_redraw_full(struct Menu *menu)
307{
309 mutt_window_clear(menu->win);
310
311 menu->page_len = menu->win->state.rows;
312
314}
315
320void menu_redraw_index(struct Menu *menu)
321{
322 char buf[1024] = { 0 };
323 struct AttrColor *ac = NULL;
324
325 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
326 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
328 for (int i = menu->top; i < (menu->top + menu->page_len); i++)
329 {
330 if (i < menu->max)
331 {
332 ac = menu->color(menu, i);
333
334 menu->make_entry(menu, buf, sizeof(buf), i);
335 menu_pad_string(menu, buf, sizeof(buf));
336
338 mutt_window_move(menu->win, 0, i - menu->top);
339
340 if (i == menu->current)
341 mutt_curses_set_color(ac_ind);
342
343 if (c_arrow_cursor)
344 {
345 if (i == menu->current)
346 {
347 mutt_window_addstr(menu->win, c_arrow_string);
349 mutt_window_addch(menu->win, ' ');
350 }
351 else
352 {
353 /* Print space chars to match the screen width of `$arrow_string` */
354 mutt_window_printf(menu->win, "%*s", mutt_strwidth(c_arrow_string) + 1, "");
355 }
356 }
357
358 if ((i == menu->current) && !c_arrow_cursor)
359 print_enriched_string(menu->win, i, ac, ac_ind, (unsigned char *) buf, menu->sub);
360 else
361 print_enriched_string(menu->win, i, ac, NULL, (unsigned char *) buf, menu->sub);
362 }
363 else
364 {
366 mutt_window_clearline(menu->win, i - menu->top);
367 }
368 }
371}
372
377void menu_redraw_motion(struct Menu *menu)
378{
379 char buf[1024] = { 0 };
380
381 /* Note: menu->color() for the index can end up retrieving a message
382 * over imap (if matching against ~h for instance). This can
383 * generate status messages. So we want to call it *before* we
384 * position the cursor for drawing. */
385 struct AttrColor *old_color = menu->color(menu, menu->old_current);
386 mutt_window_move(menu->win, 0, menu->old_current - menu->top);
387 mutt_curses_set_color(old_color);
388
389 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
390 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
392 if (c_arrow_cursor)
393 {
394 /* clear the arrow */
395 /* Print space chars to match the screen width of `$arrow_string` */
396 mutt_window_printf(menu->win, "%*s", mutt_strwidth(c_arrow_string) + 1, "");
398
399 menu->make_entry(menu, buf, sizeof(buf), menu->old_current);
400 menu_pad_string(menu, buf, sizeof(buf));
401 mutt_window_move(menu->win, mutt_strwidth(c_arrow_string) + 1,
402 menu->old_current - menu->top);
403 print_enriched_string(menu->win, menu->old_current, old_color, NULL,
404 (unsigned char *) buf, menu->sub);
405
406 /* now draw it in the new location */
407 mutt_curses_set_color(ac_ind);
408 mutt_window_mvaddstr(menu->win, 0, menu->current - menu->top, c_arrow_string);
409 }
410 else
411 {
413 /* erase the current indicator */
414 menu->make_entry(menu, buf, sizeof(buf), menu->old_current);
415 menu_pad_string(menu, buf, sizeof(buf));
416 print_enriched_string(menu->win, menu->old_current, old_color, NULL,
417 (unsigned char *) buf, menu->sub);
418
419 /* now draw the new one to reflect the change */
420 struct AttrColor *cur_color = menu->color(menu, menu->current);
421 cur_color = merged_color_overlay(cur_color, ac_ind);
422 menu->make_entry(menu, buf, sizeof(buf), menu->current);
423 menu_pad_string(menu, buf, sizeof(buf));
424 mutt_window_move(menu->win, 0, menu->current - menu->top);
425 mutt_curses_set_color(cur_color);
426 print_enriched_string(menu->win, menu->current, cur_color, ac_ind,
427 (unsigned char *) buf, menu->sub);
428 }
430}
431
436void menu_redraw_current(struct Menu *menu)
437{
438 char buf[1024] = { 0 };
439 struct AttrColor *ac = menu->color(menu, menu->current);
440
441 mutt_window_move(menu->win, 0, menu->current - menu->top);
442 menu->make_entry(menu, buf, sizeof(buf), menu->current);
443 menu_pad_string(menu, buf, sizeof(buf));
444
446 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
447 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
448 if (c_arrow_cursor)
449 {
450 mutt_curses_set_color(ac_ind);
451 mutt_window_addstr(menu->win, c_arrow_string);
453 mutt_window_addch(menu->win, ' ');
454 menu_pad_string(menu, buf, sizeof(buf));
455 print_enriched_string(menu->win, menu->current, ac, NULL,
456 (unsigned char *) buf, menu->sub);
457 }
458 else
459 {
460 print_enriched_string(menu->win, menu->current, ac, ac_ind,
461 (unsigned char *) buf, menu->sub);
462 }
464}
465
472int menu_redraw(struct Menu *menu)
473{
474 /* See if all or part of the screen needs to be updated. */
475 if (menu->redraw & MENU_REDRAW_FULL)
476 menu_redraw_full(menu);
477
478 if (menu->redraw & MENU_REDRAW_INDEX)
479 menu_redraw_index(menu);
480 else if (menu->redraw & MENU_REDRAW_MOTION)
481 menu_redraw_motion(menu);
482 else if (menu->redraw == MENU_REDRAW_CURRENT)
484
485 return OP_NULL;
486}
Color and attribute parsing.
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a colour id.
Definition: regex.c:184
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition: simple.c:74
@ MT_COLOR_INDICATOR
Selected item in list.
Definition: color.h:52
@ MT_COLOR_INDEX_TAG
Index: tag field (G)
Definition: color.h:90
@ MT_COLOR_TREE
Index: tree-drawing characters.
Definition: color.h:77
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:57
@ MT_COLOR_INDEX
Index: default colour.
Definition: color.h:81
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:638
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:906
@ JUSTIFY_LEFT
Left justify the text.
Definition: curs_lib.h:42
void menu_redraw_current(struct Menu *menu)
Redraw the current menu.
Definition: draw.c:436
static void print_enriched_string(struct MuttWindow *win, int index, struct AttrColor *ac_def, struct AttrColor *ac_ind, unsigned char *s, struct ConfigSubset *sub)
Display a string with embedded colours and graphics.
Definition: draw.c:109
void menu_redraw_index(struct Menu *menu)
Force the redraw of the index.
Definition: draw.c:320
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:472
void menu_redraw_full(struct Menu *menu)
Force the redraw of the Menu.
Definition: draw.c:306
static void menu_pad_string(struct Menu *menu, char *buf, size_t buflen)
Pad a string with spaces for display in the Menu.
Definition: draw.c:288
static struct AttrColor * get_color(int index, unsigned char *s)
Choose a colour for a line of the index.
Definition: draw.c:55
void menu_redraw_motion(struct Menu *menu)
Force the redraw of the list part of the menu.
Definition: draw.c:377
Structs that make up an email.
bool mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: exec.c:1116
Convenience wrapper for the gui headers.
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
GUI manage the main index (list of emails)
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:618
#define FREE(x)
Definition: memory.h:43
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:60
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:57
#define MENU_REDRAW_NO_FLAGS
No flags are set.
Definition: lib.h:56
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:59
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:58
struct AttrColor * merged_color_overlay(struct AttrColor *base, struct AttrColor *over)
Combine two colours.
Definition: merged.c:109
bool CharsetIsUtf8
Is the user's current character set utf-8?
Definition: charset.c:62
Convenience wrapper for the library headers.
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:496
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
void mutt_curses_set_color(struct AttrColor *ac)
Set the colour and attributes for text.
Definition: mutt_curses.c:40
struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:81
Create/manipulate threading in emails.
@ MUTT_TREE_MAX
Definition: mutt_thread.h:57
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition: mutt_thread.h:44
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:50
@ MUTT_SPECIAL_INDEX
Colour indicator.
Definition: mutt_thread.h:59
@ MUTT_TREE_ULCORNER
Upper left corner.
Definition: mutt_thread.h:45
@ MUTT_TREE_EQUALS
Equals (for threads)
Definition: mutt_thread.h:53
@ MUTT_TREE_HIDDEN
Ampersand character (for threads)
Definition: mutt_thread.h:52
@ MUTT_TREE_STAR
Star character (for threads)
Definition: mutt_thread.h:51
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:46
@ MUTT_TREE_VLINE
Vertical line.
Definition: mutt_thread.h:48
@ MUTT_TREE_MISSING
Question mark.
Definition: mutt_thread.h:56
@ MUTT_TREE_TTEE
Top T-piece.
Definition: mutt_thread.h:54
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:47
@ MUTT_TREE_SPACE
Blank space.
Definition: mutt_thread.h:49
@ MUTT_TREE_BTEE
Bottom T-piece.
Definition: mutt_thread.h:55
void mutt_window_clear(struct MuttWindow *win)
Clear a Window.
Definition: mutt_window.c:694
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:423
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:292
int mutt_window_mvaddstr(struct MuttWindow *win, int col, int row, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:306
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:229
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:408
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:393
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:380
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: mview.c:414
The "currently-open" mailbox.
All user-callable functions.
Match patterns to emails.
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:99
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define SLIST_FIRST(head)
Definition: queue.h:229
A curses colour and its attributes.
Definition: attr.h:35
A set of inherited config items.
Definition: subset.h:47
The envelope/body of an email.
Definition: email.h:37
int index
The absolute (unsorted) message number.
Definition: email.h:109
A mailbox.
Definition: mailbox.h:79
Definition: lib.h:70
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:77
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Definition: lib.h:97
int current
Current entry.
Definition: lib.h:71
MenuRedrawFlags redraw
When to redraw the screen.
Definition: lib.h:73
struct AttrColor *(* color)(struct Menu *menu, int line)
Definition: lib.h:134
int top
Entry that is the top of the current page.
Definition: lib.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: lib.h:78
int page_len
Number of entries per screen.
Definition: lib.h:75
int old_current
For driver use only.
Definition: lib.h:82
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
A regular expression and a color to highlight a line.
Definition: regex4.h:37
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: regex4.h:42
struct AttrColor attr_color
Colour and attributes to apply.
Definition: regex4.h:38
char * pattern
Pattern to match.
Definition: regex4.h:39
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
struct HashTable * TagTransforms
Lookup table of alternative tag names.
Definition: tags.c:38