NeoMutt  2025-12-11-435-g4ac674
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
draw.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.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 "core/lib.h"
38#include "gui/lib.h"
39#include "lib.h"
40#include "color/lib.h"
41#include "index/lib.h"
42#include "pattern/lib.h"
43
53static const struct AttrColor *get_color(int index, unsigned char *s)
54{
55 const int type = *s;
56 struct RegexColorList *rcl = regex_colors_get_list(type);
57 struct Mailbox *m_cur = get_current_mailbox();
58 struct Email *e = mutt_get_virt_email(m_cur, index);
59 if (!rcl || !e)
60 {
61 return simple_color_get(type);
62 }
63
64 struct RegexColor *np = NULL;
65
67 ASSERT(md);
68
69 if (type == MT_COLOR_INDEX_TAG)
70 {
71 const struct AttrColor *ac_merge = NULL;
72 STAILQ_FOREACH(np, rcl, entries)
73 {
74 if (mutt_strn_equal((const char *) (s + 1), np->pattern, strlen(np->pattern)))
75 {
76 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
77 continue;
78 }
79 const char *transform = mutt_hash_find(md->tag_transforms, np->pattern);
80 if (transform && mutt_strn_equal((const char *) (s + 1), transform, strlen(transform)))
81 {
82 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
83 }
84 }
85 return ac_merge;
86 }
87
88 const struct AttrColor *ac_merge = NULL;
89 STAILQ_FOREACH(np, rcl, entries)
90 {
92 MUTT_MATCH_FULL_ADDRESS, m_cur, e, NULL))
93 {
94 ac_merge = merged_color_overlay(ac_merge, &np->attr_color);
95 }
96 }
97
98 return ac_merge;
99}
100
110static void print_enriched_string(struct MuttWindow *win, int index,
111 const struct AttrColor *ac_def, struct AttrColor *ac_ind,
112 struct Buffer *buf, struct ConfigSubset *sub)
113{
114 wchar_t wc = 0;
115 size_t k;
116 size_t n = mutt_str_len(buf_string(buf));
117 unsigned char *s = (unsigned char *) buf->data;
118 mbstate_t mbstate = { 0 };
119
120 const bool c_ascii_chars = cs_subset_bool(sub, "ascii_chars");
121 while (*s)
122 {
123 if (*s < MUTT_TREE_MAX)
124 {
125 /* Combining tree fg color and another bg color requires having
126 * use_default_colors, because the other bg color may be undefined. */
127 mutt_curses_set_color(ac_ind);
128
129 while (*s && (*s < MUTT_TREE_MAX))
130 {
131 switch (*s)
132 {
134 if (c_ascii_chars)
135 mutt_window_addch(win, '`');
136#ifdef WACS_LLCORNER
137 else
138 add_wch(WACS_LLCORNER);
139#else
140 else if (CharsetIsUtf8)
141 mutt_window_addstr(win, "\342\224\224"); /* WACS_LLCORNER */
142 else
143 mutt_window_addch(win, ACS_LLCORNER);
144#endif
145 break;
147 if (c_ascii_chars)
148 mutt_window_addch(win, ',');
149#ifdef WACS_ULCORNER
150 else
151 add_wch(WACS_ULCORNER);
152#else
153 else if (CharsetIsUtf8)
154 mutt_window_addstr(win, "\342\224\214"); /* WACS_ULCORNER */
155 else
156 mutt_window_addch(win, ACS_ULCORNER);
157#endif
158 break;
159 case MUTT_TREE_LTEE:
160 if (c_ascii_chars)
161 mutt_window_addch(win, '|');
162#ifdef WACS_LTEE
163 else
164 add_wch(WACS_LTEE);
165#else
166 else if (CharsetIsUtf8)
167 mutt_window_addstr(win, "\342\224\234"); /* WACS_LTEE */
168 else
169 mutt_window_addch(win, ACS_LTEE);
170#endif
171 break;
172 case MUTT_TREE_HLINE:
173 if (c_ascii_chars)
174 mutt_window_addch(win, '-');
175#ifdef WACS_HLINE
176 else
177 add_wch(WACS_HLINE);
178#else
179 else if (CharsetIsUtf8)
180 mutt_window_addstr(win, "\342\224\200"); /* WACS_HLINE */
181 else
182 mutt_window_addch(win, ACS_HLINE);
183#endif
184 break;
185 case MUTT_TREE_VLINE:
186 if (c_ascii_chars)
187 mutt_window_addch(win, '|');
188#ifdef WACS_VLINE
189 else
190 add_wch(WACS_VLINE);
191#else
192 else if (CharsetIsUtf8)
193 mutt_window_addstr(win, "\342\224\202"); /* WACS_VLINE */
194 else
195 mutt_window_addch(win, ACS_VLINE);
196#endif
197 break;
198 case MUTT_TREE_TTEE:
199 if (c_ascii_chars)
200 mutt_window_addch(win, '-');
201#ifdef WACS_TTEE
202 else
203 add_wch(WACS_TTEE);
204#else
205 else if (CharsetIsUtf8)
206 mutt_window_addstr(win, "\342\224\254"); /* WACS_TTEE */
207 else
208 mutt_window_addch(win, ACS_TTEE);
209#endif
210 break;
211 case MUTT_TREE_BTEE:
212 if (c_ascii_chars)
213 mutt_window_addch(win, '-');
214#ifdef WACS_BTEE
215 else
216 add_wch(WACS_BTEE);
217#else
218 else if (CharsetIsUtf8)
219 mutt_window_addstr(win, "\342\224\264"); /* WACS_BTEE */
220 else
221 mutt_window_addch(win, ACS_BTEE);
222#endif
223 break;
224 case MUTT_TREE_SPACE:
225 mutt_window_addch(win, ' ');
226 break;
227 case MUTT_TREE_RARROW:
228 mutt_window_addch(win, '>');
229 break;
230 case MUTT_TREE_STAR:
231 mutt_window_addch(win, '*'); /* fake thread indicator */
232 break;
233 case MUTT_TREE_HIDDEN:
234 mutt_window_addch(win, '&');
235 break;
236 case MUTT_TREE_EQUALS:
237 mutt_window_addch(win, '=');
238 break;
240 mutt_window_addch(win, '?');
241 break;
242 }
243 s++;
244 n--;
245 }
246 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, ac_ind);
247 mutt_curses_set_color(ac_merge);
248 }
249 else if ((*s == MUTT_SPECIAL_INDEX) && (n >= 2))
250 {
251 s++;
252 if (*s == MT_COLOR_INDEX)
253 {
254 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, ac_ind);
255 mutt_curses_set_color(ac_merge);
256 }
257 else
258 {
259 const struct AttrColor *color = get_color(index, s);
260 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, color);
261 ac_merge = merged_color_overlay(ac_merge, ac_ind);
262
263 mutt_curses_set_color(ac_merge);
264 }
265 s++;
266 n -= 2;
267 }
268 else if ((k = mbrtowc(&wc, (char *) s, n, &mbstate)) > 0)
269 {
270 mutt_window_addnstr(win, (char *) s, k);
271 s += k;
272 n -= k;
273 }
274 else
275 {
276 break;
277 }
278 }
279}
280
288static void menu_pad_string(struct Menu *menu, struct Buffer *buf)
289{
290 int max_cols = menu->win->state.cols;
291 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
292 if (c_arrow_cursor)
293 {
294 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
295 if (max_cols > 0)
296 max_cols -= (mutt_strwidth(c_arrow_string) + 1);
297 }
298
299 int buf_cols = mutt_strwidth(buf_string(buf));
300 for (; buf_cols < max_cols; buf_cols++)
301 {
302 buf_addch(buf, ' ');
303 }
304}
305
310void menu_redraw_full(struct Menu *menu)
311{
313 mutt_window_clear(menu->win);
314
315 menu->page_len = menu->win->state.rows;
316
318}
319
324void menu_redraw_index(struct Menu *menu)
325{
326 struct Buffer *buf = buf_pool_get();
327 const struct AttrColor *ac = NULL;
328
329 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
330 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
331 const int arrow_width = mutt_strwidth(c_arrow_string);
332 struct AttrColor *ac_ind = menu->show_indicator ? simple_color_get(MT_COLOR_INDICATOR) : NULL;
333 for (int i = menu->top; i < (menu->top + menu->page_len); i++)
334 {
335 if (i < menu->max)
336 {
337 ac = menu->color(menu, i);
338
339 buf_reset(buf);
340 menu->make_entry(menu, i, menu->win->state.cols, buf);
341 menu_pad_string(menu, buf);
342
344 mutt_window_move(menu->win, i - menu->top, 0);
345
346 if (i == menu->current)
347 mutt_curses_set_color(ac_ind);
348
349 if (c_arrow_cursor)
350 {
351 if (i == menu->current)
352 {
353 mutt_window_addstr(menu->win, c_arrow_string);
355 mutt_window_addch(menu->win, ' ');
356 }
357 else
358 {
359 /* Print space chars to match the screen width of `$arrow_string` */
360 mutt_window_printf(menu->win, "%*s", arrow_width + 1, "");
361 }
362 }
363
364 if ((i == menu->current) && !c_arrow_cursor)
365 {
366 print_enriched_string(menu->win, i, ac, ac_ind, buf, menu->sub);
367 }
368 else
369 {
370 print_enriched_string(menu->win, i, ac, NULL, buf, menu->sub);
371 }
372 }
373 else
374 {
376 mutt_window_clearline(menu->win, i - menu->top);
377 }
378 }
381 buf_pool_release(&buf);
382}
383
388void menu_redraw_motion(struct Menu *menu)
389{
390 struct Buffer *buf = buf_pool_get();
391
392 /* Note: menu->color() for the index can end up retrieving a message
393 * over imap (if matching against ~h for instance). This can
394 * generate status messages. So we want to call it *before* we
395 * position the cursor for drawing. */
396 const struct AttrColor *old_color = menu->color(menu, menu->old_current);
397 mutt_window_move(menu->win, menu->old_current - menu->top, 0);
398 mutt_curses_set_color(old_color);
399
400 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
401 struct AttrColor *ac_ind = menu->show_indicator ? simple_color_get(MT_COLOR_INDICATOR) : NULL;
402 if (c_arrow_cursor)
403 {
404 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
405 const int arrow_width = mutt_strwidth(c_arrow_string);
406 /* clear the arrow */
407 /* Print space chars to match the screen width of `$arrow_string` */
408 mutt_window_printf(menu->win, "%*s", arrow_width + 1, "");
410
411 menu->make_entry(menu, menu->old_current, menu->win->state.cols, buf);
412 menu_pad_string(menu, buf);
413 mutt_window_move(menu->win, menu->old_current - menu->top, arrow_width + 1);
414 print_enriched_string(menu->win, menu->old_current, old_color, NULL, buf, menu->sub);
415
416 /* now draw it in the new location */
417 mutt_curses_set_color(ac_ind);
418 mutt_window_move(menu->win, menu->current - menu->top, 0);
419 mutt_window_addstr(menu->win, c_arrow_string);
420 }
421 else
422 {
424 /* erase the current indicator */
425 menu->make_entry(menu, menu->old_current, menu->win->state.cols, buf);
426 menu_pad_string(menu, buf);
427 print_enriched_string(menu->win, menu->old_current, old_color, NULL, buf, menu->sub);
428
429 /* now draw the new one to reflect the change */
430 const struct AttrColor *cur_color = menu->color(menu, menu->current);
431 cur_color = merged_color_overlay(cur_color, ac_ind);
432 buf_reset(buf);
433 menu->make_entry(menu, menu->current, menu->win->state.cols, buf);
434 menu_pad_string(menu, buf);
435 mutt_window_move(menu->win, menu->current - menu->top, 0);
436 mutt_curses_set_color(cur_color);
437 print_enriched_string(menu->win, menu->current, cur_color, ac_ind, buf, menu->sub);
438 }
440 buf_pool_release(&buf);
441}
442
447void menu_redraw_current(struct Menu *menu)
448{
449 struct Buffer *buf = buf_pool_get();
450 const struct AttrColor *ac = menu->color(menu, menu->current);
451
452 mutt_window_move(menu->win, menu->current - menu->top, 0);
453 menu->make_entry(menu, menu->current, menu->win->state.cols, buf);
454 menu_pad_string(menu, buf);
455
456 struct AttrColor *ac_ind = menu->show_indicator ? simple_color_get(MT_COLOR_INDICATOR) : NULL;
457 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
458 if (c_arrow_cursor)
459 {
460 mutt_curses_set_color(ac_ind);
461 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
462 mutt_window_addstr(menu->win, c_arrow_string);
464 mutt_window_addch(menu->win, ' ');
465 menu_pad_string(menu, buf);
466 print_enriched_string(menu->win, menu->current, ac, NULL, buf, menu->sub);
467 }
468 else
469 {
470 print_enriched_string(menu->win, menu->current, ac, ac_ind, buf, menu->sub);
471 }
473 buf_pool_release(&buf);
474}
475
482int menu_redraw(struct Menu *menu)
483{
484 /* See if all or part of the screen needs to be updated. */
485 if (menu->redraw & MENU_REDRAW_FULL)
486 menu_redraw_full(menu);
487
488 if (menu->redraw & MENU_REDRAW_INDEX)
489 menu_redraw_index(menu);
490 else if (menu->redraw & MENU_REDRAW_MOTION)
491 menu_redraw_motion(menu);
492 else if (menu->redraw == MENU_REDRAW_CURRENT)
494
495 return OP_NULL;
496}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
Color and attribute parsing.
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a Colour ID.
Definition regex.c:205
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition simple.c:95
@ MT_COLOR_INDICATOR
Selected item in list.
Definition color.h:49
@ MT_COLOR_INDEX_TAG
Index: tag field (G)
Definition color.h:95
@ MT_COLOR_NORMAL
Plain text.
Definition color.h:53
@ MT_COLOR_INDEX
Index: default colour.
Definition color.h:86
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition curs_lib.c:444
void menu_redraw_current(struct Menu *menu)
Redraw the current menu.
Definition draw.c:447
static const struct AttrColor * get_color(int index, unsigned char *s)
Choose a colour for a line of the index.
Definition draw.c:53
void menu_redraw_index(struct Menu *menu)
Force the redraw of the index.
Definition draw.c:324
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition draw.c:482
void menu_redraw_full(struct Menu *menu)
Force the redraw of the Menu.
Definition draw.c:310
static void menu_pad_string(struct Menu *menu, struct Buffer *buf)
Pad a string with spaces for display in the Menu.
Definition draw.c:288
static void print_enriched_string(struct MuttWindow *win, int index, const struct AttrColor *ac_def, struct AttrColor *ac_ind, struct Buffer *buf, struct ConfigSubset *sub)
Display a string with embedded colours and graphics.
Definition draw.c:110
void menu_redraw_motion(struct Menu *menu)
Force the redraw of the list part of the menu.
Definition draw.c:388
Structs that make up an email.
Convenience wrapper for the gui headers.
@ MUTT_TREE_MAX
Definition thread.h:70
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition thread.h:57
@ MUTT_TREE_RARROW
Right arrow.
Definition thread.h:63
@ MUTT_SPECIAL_INDEX
Colour indicator.
Definition thread.h:72
@ MUTT_TREE_ULCORNER
Upper left corner.
Definition thread.h:58
@ MUTT_TREE_EQUALS
Equals (for threads)
Definition thread.h:66
@ MUTT_TREE_HIDDEN
Ampersand character (for threads)
Definition thread.h:65
@ MUTT_TREE_STAR
Star character (for threads)
Definition thread.h:64
@ MUTT_TREE_LTEE
Left T-piece.
Definition thread.h:59
@ MUTT_TREE_VLINE
Vertical line.
Definition thread.h:61
@ MUTT_TREE_MISSING
Question mark.
Definition thread.h:69
@ MUTT_TREE_TTEE
Top T-piece.
Definition thread.h:67
@ MUTT_TREE_HLINE
Horizontal line.
Definition thread.h:60
@ MUTT_TREE_SPACE
Blank space.
Definition thread.h:62
@ MUTT_TREE_BTEE
Bottom T-piece.
Definition thread.h:68
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:364
GUI manage the main index (list of emails)
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition index.c:721
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
const struct AttrColor * merged_color_overlay(const struct AttrColor *base, const struct AttrColor *over)
Combine two colours.
Definition merged.c:107
@ MODULE_ID_EMAIL
ModuleEmail, Email code
Definition module_api.h:64
bool CharsetIsUtf8
Is the user's current character set utf-8?
Definition charset.c:66
Convenience wrapper for the library headers.
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:429
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:500
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:79
void mutt_curses_set_color(const struct AttrColor *ac)
Set the colour and attributes for text.
Definition mutt_curses.c:38
void mutt_window_clear(struct MuttWindow *win)
Clear a Window.
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition mview.c:415
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:585
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:1146
Match patterns to emails.
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition lib.h:107
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define SLIST_FIRST(head)
Definition queue.h:227
#define ASSERT(COND)
Definition signal2.h:59
A curses colour and its attributes.
Definition attr.h:65
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
A set of inherited config items.
Definition subset.h:46
Email private Module data.
Definition module_data.h:32
struct HashTable * tag_transforms
Hash Table: "inbox" -> "i" - Alternative tag names.
Definition module_data.h:44
The envelope/body of an email.
Definition email.h:39
int index
The absolute (unsorted) message number.
Definition email.h:110
A mailbox.
Definition mailbox.h:78
Definition lib.h:80
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:88
int current
Current entry.
Definition lib.h:81
const struct AttrColor *(* color)(struct Menu *menu, int line)
Definition lib.h:145
MenuRedrawFlags redraw
When to redraw the screen.
Definition lib.h:83
bool show_indicator
Show the Indicator colour.
Definition lib.h:87
int top
Entry that is the top of the current page.
Definition lib.h:92
int(* make_entry)(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
Definition lib.h:108
struct ConfigSubset * sub
Inherited config items.
Definition lib.h:89
int page_len
Number of entries per screen.
Definition lib.h:85
int old_current
For driver use only.
Definition lib.h:93
struct WindowState state
Current state of the Window.
Container for Accounts, Notifications.
Definition neomutt.h:41
A regular expression and a color to highlight a line.
Definition regex4.h:35
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition regex4.h:40
struct AttrColor attr_color
Colour and attributes to apply.
Definition regex4.h:36
char * pattern
Pattern to match.
Definition regex4.h:37
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