NeoMutt  2022-04-29-215-gc12b98
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 struct RegexColorList *rcl = NULL;
58 struct RegexColor *np = NULL;
59 struct Mailbox *m_cur = get_current_mailbox();
60 struct Email *e = mutt_get_virt_email(m_cur, index);
61 int type = *s;
62
63 switch (type)
64 {
67 break;
70 break;
73 break;
75 {
76 struct AttrColor *ac_merge = NULL;
78 {
79 if (mutt_strn_equal((const char *) (s + 1), np->pattern, strlen(np->pattern)))
80 {
81 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
82 continue;
83 }
84 const char *transform = mutt_hash_find(TagTransforms, np->pattern);
85 if (transform && mutt_strn_equal((const char *) (s + 1), transform, strlen(transform)))
86 {
87 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
88 }
89 }
90 return ac_merge;
91 }
92 default:
93 return simple_color_get(type);
94 }
95
96 struct AttrColor *ac_merge = NULL;
97 STAILQ_FOREACH(np, rcl, entries)
98 {
100 MUTT_MATCH_FULL_ADDRESS, m_cur, e, NULL))
101 {
102 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
103 }
104 }
105
106 return ac_merge;
107}
108
118static void print_enriched_string(struct MuttWindow *win, int index,
119 struct AttrColor *ac_def, struct AttrColor *ac_ind,
120 unsigned char *s, struct ConfigSubset *sub)
121{
122 wchar_t wc = 0;
123 size_t k;
124 size_t n = mutt_str_len((char *) s);
125 mbstate_t mbstate = { 0 };
126
127 const bool c_ascii_chars = cs_subset_bool(sub, "ascii_chars");
128 while (*s)
129 {
130 if (*s < MUTT_TREE_MAX)
131 {
133 ac_merge = merged_color_overlay(ac_merge, ac_ind);
134
135 /* Combining tree fg color and another bg color requires having
136 * use_default_colors, because the other bg color may be undefined. */
137 mutt_curses_set_color(ac_merge);
138
139 while (*s && (*s < MUTT_TREE_MAX))
140 {
141 switch (*s)
142 {
144 if (c_ascii_chars)
145 mutt_window_addch(win, '`');
146#ifdef WACS_LLCORNER
147 else
148 add_wch(WACS_LLCORNER);
149#else
150 else if (CharsetIsUtf8)
151 mutt_window_addstr(win, "\342\224\224"); /* WACS_LLCORNER */
152 else
153 mutt_window_addch(win, ACS_LLCORNER);
154#endif
155 break;
157 if (c_ascii_chars)
158 mutt_window_addch(win, ',');
159#ifdef WACS_ULCORNER
160 else
161 add_wch(WACS_ULCORNER);
162#else
163 else if (CharsetIsUtf8)
164 mutt_window_addstr(win, "\342\224\214"); /* WACS_ULCORNER */
165 else
166 mutt_window_addch(win, ACS_ULCORNER);
167#endif
168 break;
169 case MUTT_TREE_LTEE:
170 if (c_ascii_chars)
171 mutt_window_addch(win, '|');
172#ifdef WACS_LTEE
173 else
174 add_wch(WACS_LTEE);
175#else
176 else if (CharsetIsUtf8)
177 mutt_window_addstr(win, "\342\224\234"); /* WACS_LTEE */
178 else
179 mutt_window_addch(win, ACS_LTEE);
180#endif
181 break;
182 case MUTT_TREE_HLINE:
183 if (c_ascii_chars)
184 mutt_window_addch(win, '-');
185#ifdef WACS_HLINE
186 else
187 add_wch(WACS_HLINE);
188#else
189 else if (CharsetIsUtf8)
190 mutt_window_addstr(win, "\342\224\200"); /* WACS_HLINE */
191 else
192 mutt_window_addch(win, ACS_HLINE);
193#endif
194 break;
195 case MUTT_TREE_VLINE:
196 if (c_ascii_chars)
197 mutt_window_addch(win, '|');
198#ifdef WACS_VLINE
199 else
200 add_wch(WACS_VLINE);
201#else
202 else if (CharsetIsUtf8)
203 mutt_window_addstr(win, "\342\224\202"); /* WACS_VLINE */
204 else
205 mutt_window_addch(win, ACS_VLINE);
206#endif
207 break;
208 case MUTT_TREE_TTEE:
209 if (c_ascii_chars)
210 mutt_window_addch(win, '-');
211#ifdef WACS_TTEE
212 else
213 add_wch(WACS_TTEE);
214#else
215 else if (CharsetIsUtf8)
216 mutt_window_addstr(win, "\342\224\254"); /* WACS_TTEE */
217 else
218 mutt_window_addch(win, ACS_TTEE);
219#endif
220 break;
221 case MUTT_TREE_BTEE:
222 if (c_ascii_chars)
223 mutt_window_addch(win, '-');
224#ifdef WACS_BTEE
225 else
226 add_wch(WACS_BTEE);
227#else
228 else if (CharsetIsUtf8)
229 mutt_window_addstr(win, "\342\224\264"); /* WACS_BTEE */
230 else
231 mutt_window_addch(win, ACS_BTEE);
232#endif
233 break;
234 case MUTT_TREE_SPACE:
235 mutt_window_addch(win, ' ');
236 break;
237 case MUTT_TREE_RARROW:
238 mutt_window_addch(win, '>');
239 break;
240 case MUTT_TREE_STAR:
241 mutt_window_addch(win, '*'); /* fake thread indicator */
242 break;
243 case MUTT_TREE_HIDDEN:
244 mutt_window_addch(win, '&');
245 break;
246 case MUTT_TREE_EQUALS:
247 mutt_window_addch(win, '=');
248 break;
250 mutt_window_addch(win, '?');
251 break;
252 }
253 s++;
254 n--;
255 }
256 ac_merge = merged_color_overlay(ac_def, ac_ind);
257 mutt_curses_set_color(ac_merge);
258 }
259 else if (*s == MUTT_SPECIAL_INDEX)
260 {
261 s++;
262 if (*s == MT_COLOR_INDEX)
263 {
264 struct AttrColor *ac_merge = merged_color_overlay(ac_def, ac_ind);
265 mutt_curses_set_color(ac_merge);
266 }
267 else
268 {
269 struct AttrColor *color = get_color(index, s);
270 struct AttrColor *ac_merge = merged_color_overlay(ac_def, color);
271 ac_merge = merged_color_overlay(ac_merge, ac_ind);
272
273 mutt_curses_set_color(ac_merge);
274 }
275 s++;
276 n -= 2;
277 }
278 else if ((k = mbrtowc(&wc, (char *) s, n, &mbstate)) > 0)
279 {
280 mutt_window_addnstr(win, (char *) s, k);
281 s += k;
282 n -= k;
283 }
284 else
285 break;
286 }
287}
288
297static void menu_pad_string(struct Menu *menu, char *buf, size_t buflen)
298{
299 char *scratch = mutt_str_dup(buf);
300 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
301 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
302 int shift = c_arrow_cursor ? mutt_strwidth(c_arrow_string) + 1 : 0;
303 int cols = menu->win->state.cols - shift;
304
305 mutt_simple_format(buf, buflen, cols, cols, JUSTIFY_LEFT, ' ', scratch,
306 mutt_str_len(scratch), true);
307 buf[buflen - 1] = '\0';
308 FREE(&scratch);
309}
310
315void menu_redraw_full(struct Menu *menu)
316{
318 mutt_window_clear(menu->win);
319
320 menu->page_len = menu->win->state.rows;
321
323}
324
329void menu_redraw_index(struct Menu *menu)
330{
331 char buf[1024] = { 0 };
332 struct AttrColor *ac = NULL;
333
334 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
335 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
337 for (int i = menu->top; i < (menu->top + menu->page_len); i++)
338 {
339 if (i < menu->max)
340 {
341 ac = menu->color(menu, i);
342
343 menu->make_entry(menu, buf, sizeof(buf), i);
344 menu_pad_string(menu, buf, sizeof(buf));
345
347 mutt_window_move(menu->win, 0, i - menu->top);
348
349 if (i == menu->current)
350 mutt_curses_set_color(ac_ind);
351
352 if (c_arrow_cursor)
353 {
354 if (i == menu->current)
355 {
356 mutt_window_addstr(menu->win, c_arrow_string);
358 mutt_window_addch(menu->win, ' ');
359 }
360 else
361 {
362 /* Print space chars to match the screen width of `$arrow_string` */
363 mutt_window_printf(menu->win, "%*s", mutt_strwidth(c_arrow_string) + 1, "");
364 }
365 }
366
367 if ((i == menu->current) && !c_arrow_cursor)
368 print_enriched_string(menu->win, i, ac, ac_ind, (unsigned char *) buf, menu->sub);
369 else
370 print_enriched_string(menu->win, i, ac, NULL, (unsigned char *) buf, menu->sub);
371 }
372 else
373 {
375 mutt_window_clearline(menu->win, i - menu->top);
376 }
377 }
380}
381
386void menu_redraw_motion(struct Menu *menu)
387{
388 char buf[1024] = { 0 };
389
390 /* Note: menu->color() for the index can end up retrieving a message
391 * over imap (if matching against ~h for instance). This can
392 * generate status messages. So we want to call it *before* we
393 * position the cursor for drawing. */
394 struct AttrColor *old_color = menu->color(menu, menu->old_current);
395 mutt_window_move(menu->win, 0, menu->old_current - menu->top);
396 mutt_curses_set_color(old_color);
397
398 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
399 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
401 if (c_arrow_cursor)
402 {
403 /* clear the arrow */
404 /* Print space chars to match the screen width of `$arrow_string` */
405 mutt_window_printf(menu->win, "%*s", mutt_strwidth(c_arrow_string) + 1, "");
407
408 menu->make_entry(menu, buf, sizeof(buf), menu->old_current);
409 menu_pad_string(menu, buf, sizeof(buf));
410 mutt_window_move(menu->win, mutt_strwidth(c_arrow_string) + 1,
411 menu->old_current - menu->top);
412 print_enriched_string(menu->win, menu->old_current, old_color, NULL,
413 (unsigned char *) buf, menu->sub);
414
415 /* now draw it in the new location */
416 mutt_curses_set_color(ac_ind);
417 mutt_window_mvaddstr(menu->win, 0, menu->current - menu->top, c_arrow_string);
418 }
419 else
420 {
422 /* erase the current indicator */
423 menu->make_entry(menu, buf, sizeof(buf), menu->old_current);
424 menu_pad_string(menu, buf, sizeof(buf));
425 print_enriched_string(menu->win, menu->old_current, old_color, NULL,
426 (unsigned char *) buf, menu->sub);
427
428 /* now draw the new one to reflect the change */
429 struct AttrColor *cur_color = menu->color(menu, menu->current);
430 cur_color = merged_color_overlay(cur_color, ac_ind);
431 menu->make_entry(menu, buf, sizeof(buf), menu->current);
432 menu_pad_string(menu, buf, sizeof(buf));
433 mutt_window_move(menu->win, 0, menu->current - menu->top);
434 mutt_curses_set_color(cur_color);
435 print_enriched_string(menu->win, menu->current, cur_color, ac_ind,
436 (unsigned char *) buf, menu->sub);
437 }
439}
440
445void menu_redraw_current(struct Menu *menu)
446{
447 char buf[1024] = { 0 };
448 struct AttrColor *ac = menu->color(menu, menu->current);
449
450 mutt_window_move(menu->win, 0, menu->current - menu->top);
451 menu->make_entry(menu, buf, sizeof(buf), menu->current);
452 menu_pad_string(menu, buf, sizeof(buf));
453
455 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
456 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
457 if (c_arrow_cursor)
458 {
459 mutt_curses_set_color(ac_ind);
460 mutt_window_addstr(menu->win, c_arrow_string);
462 mutt_window_addch(menu->win, ' ');
463 menu_pad_string(menu, buf, sizeof(buf));
464 print_enriched_string(menu->win, menu->current, ac, NULL,
465 (unsigned char *) buf, menu->sub);
466 }
467 else
468 {
469 print_enriched_string(menu->win, menu->current, ac, ac_ind,
470 (unsigned char *) buf, menu->sub);
471 }
473}
474
481int menu_redraw(struct Menu *menu)
482{
483 /* See if all or part of the screen needs to be updated. */
484 if (menu->redraw & MENU_REDRAW_FULL)
485 menu_redraw_full(menu);
486
487 if (menu->redraw & MENU_REDRAW_INDEX)
488 menu_redraw_index(menu);
489 else if (menu->redraw & MENU_REDRAW_MOTION)
490 menu_redraw_motion(menu);
491 else if (menu->redraw == MENU_REDRAW_CURRENT)
493
494 return OP_NULL;
495}
Color and attribute parsing.
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a colour id.
Definition: regex.c:166
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition: simple.c:74
@ MT_COLOR_INDEX_AUTHOR
Index: author field (takes a pattern)
Definition: color.h:78
@ MT_COLOR_INDICATOR
Selected item in list.
Definition: color.h:49
@ MT_COLOR_INDEX_SUBJECT
Index: subject field (takes a pattern)
Definition: color.h:80
@ MT_COLOR_INDEX_TAG
Index: tag field (g, takes a pattern)
Definition: color.h:81
@ MT_COLOR_TREE
Index: tree-drawing characters.
Definition: color.h:73
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:54
@ MT_COLOR_INDEX
Index: default colour (takes a pattern)
Definition: color.h:77
@ MT_COLOR_INDEX_FLAGS
Index: flags field (takes a pattern)
Definition: color.h:79
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:639
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:907
@ 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:445
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:118
void menu_redraw_index(struct Menu *menu)
Force the redraw of the index.
Definition: draw.c:329
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:481
void menu_redraw_full(struct Menu *menu)
Force the redraw of the Menu.
Definition: draw.c:315
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:297
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:386
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:1107
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:624
#define FREE(x)
Definition: memory.h:43
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:59
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
#define MENU_REDRAW_NO_FLAGS
No flags are set.
Definition: lib.h:55
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:58
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:57
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:695
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:424
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:293
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:307
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:230
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:409
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:394
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:381
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:110
A mailbox.
Definition: mailbox.h:79
Definition: lib.h:69
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:76
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Definition: lib.h:96
int current
Current entry.
Definition: lib.h:70
MenuRedrawFlags redraw
When to redraw the screen.
Definition: lib.h:72
struct AttrColor *(* color)(struct Menu *menu, int line)
Definition: lib.h:133
int top
Entry that is the top of the current page.
Definition: lib.h:80
struct ConfigSubset * sub
Inherited config items.
Definition: lib.h:77
int page_len
Number of entries per screen.
Definition: lib.h:74
int old_current
For driver use only.
Definition: lib.h:81
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