NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "lib.h"
39#include "color/lib.h"
40#include "index/lib.h"
41#include "pattern/lib.h"
42#include "mutt_thread.h"
43#include "mview.h"
44#include "opcodes.h"
45
55static const 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 struct Mailbox *m_cur = get_current_mailbox();
60 struct Email *e = mutt_get_virt_email(m_cur, index);
61 if (!rcl || !e)
62 {
63 return simple_color_get(type);
64 }
65
66 struct RegexColor *np = NULL;
67
68 if (type == MT_COLOR_INDEX_TAG)
69 {
70 const 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 const 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 const 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 {
123 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, simple_color_get(MT_COLOR_TREE));
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 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, ac_ind);
256 mutt_curses_set_color(ac_merge);
257 }
258 else
259 {
260 const struct AttrColor *color = get_color(index, s);
261 const 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 {
277 break;
278 }
279 }
280}
281
290static void menu_pad_string(struct Menu *menu, char *buf, size_t buflen)
291{
292 char *scratch = mutt_str_dup(buf);
293 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
294 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
295 const int shift = c_arrow_cursor ? mutt_strwidth(c_arrow_string) + 1 : 0;
296 const int cols = menu->win->state.cols - shift;
297
298 mutt_simple_format(buf, buflen, cols, cols, JUSTIFY_LEFT, ' ', scratch,
299 mutt_str_len(scratch), true);
300 buf[buflen - 1] = '\0';
301 FREE(&scratch);
302}
303
308void menu_redraw_full(struct Menu *menu)
309{
311 mutt_window_clear(menu->win);
312
313 menu->page_len = menu->win->state.rows;
314
316}
317
322void menu_redraw_index(struct Menu *menu)
323{
324 char buf[1024] = { 0 };
325 const struct AttrColor *ac = NULL;
326
327 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
328 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
329 const int arrow_width = mutt_strwidth(c_arrow_string);
331 for (int i = menu->top; i < (menu->top + menu->page_len); i++)
332 {
333 if (i < menu->max)
334 {
335 ac = menu->color(menu, i);
336
337 menu->make_entry(menu, buf, sizeof(buf), i);
338 menu_pad_string(menu, buf, sizeof(buf));
339
341 mutt_window_move(menu->win, 0, i - menu->top);
342
343 if (i == menu->current)
344 mutt_curses_set_color(ac_ind);
345
346 if (c_arrow_cursor)
347 {
348 if (i == menu->current)
349 {
350 mutt_window_addstr(menu->win, c_arrow_string);
352 mutt_window_addch(menu->win, ' ');
353 }
354 else
355 {
356 /* Print space chars to match the screen width of `$arrow_string` */
357 mutt_window_printf(menu->win, "%*s", arrow_width + 1, "");
358 }
359 }
360
361 if ((i == menu->current) && !c_arrow_cursor)
362 print_enriched_string(menu->win, i, ac, ac_ind, (unsigned char *) buf, menu->sub);
363 else
364 print_enriched_string(menu->win, i, ac, NULL, (unsigned char *) buf, menu->sub);
365 }
366 else
367 {
369 mutt_window_clearline(menu->win, i - menu->top);
370 }
371 }
374}
375
380void menu_redraw_motion(struct Menu *menu)
381{
382 char buf[1024] = { 0 };
383
384 /* Note: menu->color() for the index can end up retrieving a message
385 * over imap (if matching against ~h for instance). This can
386 * generate status messages. So we want to call it *before* we
387 * position the cursor for drawing. */
388 const struct AttrColor *old_color = menu->color(menu, menu->old_current);
389 mutt_window_move(menu->win, 0, menu->old_current - menu->top);
390 mutt_curses_set_color(old_color);
391
392 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
394 if (c_arrow_cursor)
395 {
396 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
397 const int arrow_width = mutt_strwidth(c_arrow_string);
398 /* clear the arrow */
399 /* Print space chars to match the screen width of `$arrow_string` */
400 mutt_window_printf(menu->win, "%*s", arrow_width + 1, "");
402
403 menu->make_entry(menu, buf, sizeof(buf), menu->old_current);
404 menu_pad_string(menu, buf, sizeof(buf));
405 mutt_window_move(menu->win, arrow_width + 1, menu->old_current - menu->top);
406 print_enriched_string(menu->win, menu->old_current, old_color, NULL,
407 (unsigned char *) buf, menu->sub);
408
409 /* now draw it in the new location */
410 mutt_curses_set_color(ac_ind);
411 mutt_window_mvaddstr(menu->win, 0, menu->current - menu->top, c_arrow_string);
412 }
413 else
414 {
416 /* erase the current indicator */
417 menu->make_entry(menu, buf, sizeof(buf), menu->old_current);
418 menu_pad_string(menu, buf, sizeof(buf));
419 print_enriched_string(menu->win, menu->old_current, old_color, NULL,
420 (unsigned char *) buf, menu->sub);
421
422 /* now draw the new one to reflect the change */
423 const struct AttrColor *cur_color = menu->color(menu, menu->current);
424 cur_color = merged_color_overlay(cur_color, ac_ind);
425 menu->make_entry(menu, buf, sizeof(buf), menu->current);
426 menu_pad_string(menu, buf, sizeof(buf));
427 mutt_window_move(menu->win, 0, menu->current - menu->top);
428 mutt_curses_set_color(cur_color);
429 print_enriched_string(menu->win, menu->current, cur_color, ac_ind,
430 (unsigned char *) buf, menu->sub);
431 }
433}
434
439void menu_redraw_current(struct Menu *menu)
440{
441 char buf[1024] = { 0 };
442 const struct AttrColor *ac = menu->color(menu, menu->current);
443
444 mutt_window_move(menu->win, 0, menu->current - menu->top);
445 menu->make_entry(menu, buf, sizeof(buf), menu->current);
446 menu_pad_string(menu, buf, sizeof(buf));
447
449 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
450 if (c_arrow_cursor)
451 {
452 mutt_curses_set_color(ac_ind);
453 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
454 mutt_window_addstr(menu->win, c_arrow_string);
456 mutt_window_addch(menu->win, ' ');
457 menu_pad_string(menu, buf, sizeof(buf));
458 print_enriched_string(menu->win, menu->current, ac, NULL,
459 (unsigned char *) buf, menu->sub);
460 }
461 else
462 {
463 print_enriched_string(menu->win, menu->current, ac, ac_ind,
464 (unsigned char *) buf, menu->sub);
465 }
467}
468
475int menu_redraw(struct Menu *menu)
476{
477 /* See if all or part of the screen needs to be updated. */
478 if (menu->redraw & MENU_REDRAW_FULL)
479 menu_redraw_full(menu);
480
481 if (menu->redraw & MENU_REDRAW_INDEX)
482 menu_redraw_index(menu);
483 else if (menu->redraw & MENU_REDRAW_MOTION)
484 menu_redraw_motion(menu);
485 else if (menu->redraw == MENU_REDRAW_CURRENT)
487
488 return OP_NULL;
489}
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:81
@ MT_COLOR_INDICATOR
Selected item in list.
Definition: color.h:52
@ MT_COLOR_INDEX_TAG
Index: tag field (G)
Definition: color.h:92
@ MT_COLOR_TREE
Index: tree-drawing characters.
Definition: color.h:79
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:57
@ MT_COLOR_INDEX
Index: default colour.
Definition: color.h:83
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
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:361
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:642
@ JUSTIFY_LEFT
Left justify the text.
Definition: curs_lib.h:40
void menu_redraw_current(struct Menu *menu)
Redraw the current menu.
Definition: draw.c:439
static const 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_index(struct Menu *menu)
Force the redraw of the index.
Definition: draw.c:322
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:475
static void print_enriched_string(struct MuttWindow *win, int index, const 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_full(struct Menu *menu)
Force the redraw of the Menu.
Definition: draw.c:308
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:290
void menu_redraw_motion(struct Menu *menu)
Force the redraw of the list part of the menu.
Definition: draw.c:380
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:1137
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:662
#define FREE(x)
Definition: memory.h:45
#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
const struct AttrColor * merged_color_overlay(const struct AttrColor *base, const struct AttrColor *over)
Combine two colours.
Definition: merged.c:109
bool CharsetIsUtf8
Is the user's current character set utf-8?
Definition: charset.c:63
Convenience wrapper for the library headers.
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
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:497
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
const 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
void mutt_curses_set_color(const struct AttrColor *ac)
Set the colour and attributes for text.
Definition: mutt_curses.c:40
Create/manipulate threading in emails.
@ MUTT_TREE_MAX
Definition: mutt_thread.h:69
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition: mutt_thread.h:56
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:62
@ MUTT_SPECIAL_INDEX
Colour indicator.
Definition: mutt_thread.h:71
@ MUTT_TREE_ULCORNER
Upper left corner.
Definition: mutt_thread.h:57
@ MUTT_TREE_EQUALS
Equals (for threads)
Definition: mutt_thread.h:65
@ MUTT_TREE_HIDDEN
Ampersand character (for threads)
Definition: mutt_thread.h:64
@ MUTT_TREE_STAR
Star character (for threads)
Definition: mutt_thread.h:63
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:58
@ MUTT_TREE_VLINE
Vertical line.
Definition: mutt_thread.h:60
@ MUTT_TREE_MISSING
Question mark.
Definition: mutt_thread.h:68
@ MUTT_TREE_TTEE
Top T-piece.
Definition: mutt_thread.h:66
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:59
@ MUTT_TREE_SPACE
Blank space.
Definition: mutt_thread.h:61
@ MUTT_TREE_BTEE
Bottom T-piece.
Definition: mutt_thread.h:67
void mutt_window_clear(struct MuttWindow *win)
Clear a Window.
Definition: mutt_window.c:720
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:431
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:297
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:311
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:416
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:401
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:388
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: mview.c:407
View of a Mailbox.
All user-callable functions.
Match patterns to emails.
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:106
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define SLIST_FIRST(head)
Definition: queue.h:229
Key value store.
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:96
int current
Current entry.
Definition: lib.h:71
const struct AttrColor *(* color)(struct Menu *menu, int line)
Definition: lib.h:133
MenuRedrawFlags redraw
When to redraw the screen.
Definition: lib.h:73
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
Hash Table: "inbox" -> "i" - Alternative tag names.
Definition: tags.c:38