NeoMutt  2024-12-12-14-g7b49f7
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
draw.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <stdbool.h>
32#include <stddef.h>
33#include <string.h>
34#include <wchar.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "email/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#include "mutt_thread.h"
44#include "mview.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 struct Buffer *buf, struct ConfigSubset *sub)
112{
113 wchar_t wc = 0;
114 size_t k;
115 size_t n = mutt_str_len(buf_string(buf));
116 unsigned char *s = (unsigned char *) buf->data;
117 mbstate_t mbstate = { 0 };
118
119 const bool c_ascii_chars = cs_subset_bool(sub, "ascii_chars");
120 while (*s)
121 {
122 if (*s < MUTT_TREE_MAX)
123 {
124 /* Combining tree fg color and another bg color requires having
125 * use_default_colors, because the other bg color may be undefined. */
126 mutt_curses_set_color(ac_ind);
127
128 while (*s && (*s < MUTT_TREE_MAX))
129 {
130 switch (*s)
131 {
133 if (c_ascii_chars)
134 mutt_window_addch(win, '`');
135#ifdef WACS_LLCORNER
136 else
137 add_wch(WACS_LLCORNER);
138#else
139 else if (CharsetIsUtf8)
140 mutt_window_addstr(win, "\342\224\224"); /* WACS_LLCORNER */
141 else
142 mutt_window_addch(win, ACS_LLCORNER);
143#endif
144 break;
146 if (c_ascii_chars)
147 mutt_window_addch(win, ',');
148#ifdef WACS_ULCORNER
149 else
150 add_wch(WACS_ULCORNER);
151#else
152 else if (CharsetIsUtf8)
153 mutt_window_addstr(win, "\342\224\214"); /* WACS_ULCORNER */
154 else
155 mutt_window_addch(win, ACS_ULCORNER);
156#endif
157 break;
158 case MUTT_TREE_LTEE:
159 if (c_ascii_chars)
160 mutt_window_addch(win, '|');
161#ifdef WACS_LTEE
162 else
163 add_wch(WACS_LTEE);
164#else
165 else if (CharsetIsUtf8)
166 mutt_window_addstr(win, "\342\224\234"); /* WACS_LTEE */
167 else
168 mutt_window_addch(win, ACS_LTEE);
169#endif
170 break;
171 case MUTT_TREE_HLINE:
172 if (c_ascii_chars)
173 mutt_window_addch(win, '-');
174#ifdef WACS_HLINE
175 else
176 add_wch(WACS_HLINE);
177#else
178 else if (CharsetIsUtf8)
179 mutt_window_addstr(win, "\342\224\200"); /* WACS_HLINE */
180 else
181 mutt_window_addch(win, ACS_HLINE);
182#endif
183 break;
184 case MUTT_TREE_VLINE:
185 if (c_ascii_chars)
186 mutt_window_addch(win, '|');
187#ifdef WACS_VLINE
188 else
189 add_wch(WACS_VLINE);
190#else
191 else if (CharsetIsUtf8)
192 mutt_window_addstr(win, "\342\224\202"); /* WACS_VLINE */
193 else
194 mutt_window_addch(win, ACS_VLINE);
195#endif
196 break;
197 case MUTT_TREE_TTEE:
198 if (c_ascii_chars)
199 mutt_window_addch(win, '-');
200#ifdef WACS_TTEE
201 else
202 add_wch(WACS_TTEE);
203#else
204 else if (CharsetIsUtf8)
205 mutt_window_addstr(win, "\342\224\254"); /* WACS_TTEE */
206 else
207 mutt_window_addch(win, ACS_TTEE);
208#endif
209 break;
210 case MUTT_TREE_BTEE:
211 if (c_ascii_chars)
212 mutt_window_addch(win, '-');
213#ifdef WACS_BTEE
214 else
215 add_wch(WACS_BTEE);
216#else
217 else if (CharsetIsUtf8)
218 mutt_window_addstr(win, "\342\224\264"); /* WACS_BTEE */
219 else
220 mutt_window_addch(win, ACS_BTEE);
221#endif
222 break;
223 case MUTT_TREE_SPACE:
224 mutt_window_addch(win, ' ');
225 break;
226 case MUTT_TREE_RARROW:
227 mutt_window_addch(win, '>');
228 break;
229 case MUTT_TREE_STAR:
230 mutt_window_addch(win, '*'); /* fake thread indicator */
231 break;
232 case MUTT_TREE_HIDDEN:
233 mutt_window_addch(win, '&');
234 break;
235 case MUTT_TREE_EQUALS:
236 mutt_window_addch(win, '=');
237 break;
239 mutt_window_addch(win, '?');
240 break;
241 }
242 s++;
243 n--;
244 }
245 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, ac_ind);
246 mutt_curses_set_color(ac_merge);
247 }
248 else if (*s == MUTT_SPECIAL_INDEX)
249 {
250 s++;
251 if (*s == MT_COLOR_INDEX)
252 {
253 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, ac_ind);
254 mutt_curses_set_color(ac_merge);
255 }
256 else
257 {
258 const struct AttrColor *color = get_color(index, s);
259 const struct AttrColor *ac_merge = merged_color_overlay(ac_def, color);
260 ac_merge = merged_color_overlay(ac_merge, ac_ind);
261
262 mutt_curses_set_color(ac_merge);
263 }
264 s++;
265 n -= 2;
266 }
267 else if ((k = mbrtowc(&wc, (char *) s, n, &mbstate)) > 0)
268 {
269 mutt_window_addnstr(win, (char *) s, k);
270 s += k;
271 n -= k;
272 }
273 else
274 {
275 break;
276 }
277 }
278}
279
287static void menu_pad_string(struct Menu *menu, struct Buffer *buf)
288{
289 int max_cols = menu->win->state.cols;
290 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
291 if (c_arrow_cursor)
292 {
293 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
294 if (max_cols > 0)
295 max_cols -= (mutt_strwidth(c_arrow_string) + 1);
296 }
297
298 int buf_cols = mutt_strwidth(buf_string(buf));
299 for (; buf_cols < max_cols; buf_cols++)
300 {
301 buf_addch(buf, ' ');
302 }
303}
304
309void menu_redraw_full(struct Menu *menu)
310{
312 mutt_window_clear(menu->win);
313
314 menu->page_len = menu->win->state.rows;
315
317}
318
323void menu_redraw_index(struct Menu *menu)
324{
325 struct Buffer *buf = buf_pool_get();
326 const struct AttrColor *ac = NULL;
327
328 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
329 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
330 const int arrow_width = mutt_strwidth(c_arrow_string);
332 for (int i = menu->top; i < (menu->top + menu->page_len); i++)
333 {
334 if (i < menu->max)
335 {
336 ac = menu->color(menu, i);
337
338 buf_reset(buf);
339 menu->make_entry(menu, i, menu->win->state.cols, buf);
340 menu_pad_string(menu, buf);
341
343 mutt_window_move(menu->win, 0, i - menu->top);
344
345 if (i == menu->current)
346 mutt_curses_set_color(ac_ind);
347
348 if (c_arrow_cursor)
349 {
350 if (i == menu->current)
351 {
352 mutt_window_addstr(menu->win, c_arrow_string);
354 mutt_window_addch(menu->win, ' ');
355 }
356 else
357 {
358 /* Print space chars to match the screen width of `$arrow_string` */
359 mutt_window_printf(menu->win, "%*s", arrow_width + 1, "");
360 }
361 }
362
363 if ((i == menu->current) && !c_arrow_cursor)
364 {
365 print_enriched_string(menu->win, i, ac, ac_ind, buf, menu->sub);
366 }
367 else
368 {
369 print_enriched_string(menu->win, i, ac, NULL, buf, menu->sub);
370 }
371 }
372 else
373 {
375 mutt_window_clearline(menu->win, i - menu->top);
376 }
377 }
380 buf_pool_release(&buf);
381}
382
387void menu_redraw_motion(struct Menu *menu)
388{
389 struct Buffer *buf = buf_pool_get();
390
391 /* Note: menu->color() for the index can end up retrieving a message
392 * over imap (if matching against ~h for instance). This can
393 * generate status messages. So we want to call it *before* we
394 * position the cursor for drawing. */
395 const struct AttrColor *old_color = menu->color(menu, menu->old_current);
396 mutt_window_move(menu->win, 0, menu->old_current - menu->top);
397 mutt_curses_set_color(old_color);
398
399 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
401 if (c_arrow_cursor)
402 {
403 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
404 const int arrow_width = mutt_strwidth(c_arrow_string);
405 /* clear the arrow */
406 /* Print space chars to match the screen width of `$arrow_string` */
407 mutt_window_printf(menu->win, "%*s", arrow_width + 1, "");
409
410 menu->make_entry(menu, menu->old_current, menu->win->state.cols, buf);
411 menu_pad_string(menu, buf);
412 mutt_window_move(menu->win, arrow_width + 1, menu->old_current - menu->top);
413 print_enriched_string(menu->win, menu->old_current, old_color, NULL, 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, menu->old_current, menu->win->state.cols, buf);
424 menu_pad_string(menu, buf);
425 print_enriched_string(menu->win, menu->old_current, old_color, NULL, buf, menu->sub);
426
427 /* now draw the new one to reflect the change */
428 const struct AttrColor *cur_color = menu->color(menu, menu->current);
429 cur_color = merged_color_overlay(cur_color, ac_ind);
430 buf_reset(buf);
431 menu->make_entry(menu, menu->current, menu->win->state.cols, buf);
432 menu_pad_string(menu, 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, buf, menu->sub);
436 }
438 buf_pool_release(&buf);
439}
440
445void menu_redraw_current(struct Menu *menu)
446{
447 struct Buffer *buf = buf_pool_get();
448 const 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, menu->current, menu->win->state.cols, buf);
452 menu_pad_string(menu, buf);
453
455 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
456 if (c_arrow_cursor)
457 {
458 mutt_curses_set_color(ac_ind);
459 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
460 mutt_window_addstr(menu->win, c_arrow_string);
462 mutt_window_addch(menu->win, ' ');
463 menu_pad_string(menu, buf);
464 print_enriched_string(menu->win, menu->current, ac, NULL, buf, menu->sub);
465 }
466 else
467 {
468 print_enriched_string(menu->win, menu->current, ac, ac_ind, buf, menu->sub);
469 }
471 buf_pool_release(&buf);
472}
473
480int menu_redraw(struct Menu *menu)
481{
482 /* See if all or part of the screen needs to be updated. */
483 if (menu->redraw & MENU_REDRAW_FULL)
484 menu_redraw_full(menu);
485
486 if (menu->redraw & MENU_REDRAW_INDEX)
487 menu_redraw_index(menu);
488 else if (menu->redraw & MENU_REDRAW_MOTION)
489 menu_redraw_motion(menu);
490 else if (menu->redraw == MENU_REDRAW_CURRENT)
492
493 return OP_NULL;
494}
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:190
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:50
@ MT_COLOR_INDEX_TAG
Index: tag field (G)
Definition: color.h:88
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:55
@ MT_COLOR_INDEX
Index: default colour.
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: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.
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:443
void menu_redraw_current(struct Menu *menu)
Redraw the current menu.
Definition: draw.c:445
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:323
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:480
void menu_redraw_full(struct Menu *menu)
Force the redraw of the Menu.
Definition: draw.c:309
static void menu_pad_string(struct Menu *menu, struct Buffer *buf)
Pad a string with spaces for display in the Menu.
Definition: draw.c:287
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:109
void menu_redraw_motion(struct Menu *menu)
Force the redraw of the list part of the menu.
Definition: draw.c:387
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:1147
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:715
#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
const struct AttrColor * merged_color_overlay(const struct AttrColor *base, const struct AttrColor *over)
Combine two colours.
Definition: merged.c:107
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:425
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
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
Create/manipulate threading in emails.
@ MUTT_TREE_MAX
Definition: mutt_thread.h:71
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition: mutt_thread.h:58
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:64
@ MUTT_SPECIAL_INDEX
Colour indicator.
Definition: mutt_thread.h:73
@ MUTT_TREE_ULCORNER
Upper left corner.
Definition: mutt_thread.h:59
@ MUTT_TREE_EQUALS
Equals (for threads)
Definition: mutt_thread.h:67
@ MUTT_TREE_HIDDEN
Ampersand character (for threads)
Definition: mutt_thread.h:66
@ MUTT_TREE_STAR
Star character (for threads)
Definition: mutt_thread.h:65
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:60
@ MUTT_TREE_VLINE
Vertical line.
Definition: mutt_thread.h:62
@ MUTT_TREE_MISSING
Question mark.
Definition: mutt_thread.h:70
@ MUTT_TREE_TTEE
Top T-piece.
Definition: mutt_thread.h:68
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:61
@ MUTT_TREE_SPACE
Blank space.
Definition: mutt_thread.h:63
@ MUTT_TREE_BTEE
Bottom T-piece.
Definition: mutt_thread.h:69
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:417
View of a Mailbox.
Match patterns to emails.
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:106
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define SLIST_FIRST(head)
Definition: queue.h:227
Key value store.
A curses colour and its attributes.
Definition: attr.h:66
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:47
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:79
Definition: lib.h:79
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:86
int current
Current entry.
Definition: lib.h:80
const struct AttrColor *(* color)(struct Menu *menu, int line)
Definition: lib.h:143
MenuRedrawFlags redraw
When to redraw the screen.
Definition: lib.h:82
int top
Entry that is the top of the current page.
Definition: lib.h:90
int(* make_entry)(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
Definition: lib.h:106
struct ConfigSubset * sub
Inherited config items.
Definition: lib.h:87
int page_len
Number of entries per screen.
Definition: lib.h:84
int old_current
For driver use only.
Definition: lib.h:91
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:36
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: regex4.h:41
struct AttrColor attr_color
Colour and attributes to apply.
Definition: regex4.h:37
char * pattern
Pattern to match.
Definition: regex4.h:38
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:62
struct HashTable * TagTransforms
Hash Table: "inbox" -> "i" - Alternative tag names.
Definition: tags.c:41