changeset 33:791e72e43120

ui: use wchar_t to output to the screen
author David Demelier <markand@malikania.fr>
date Tue, 10 Mar 2020 20:00:00 +0100
parents 1dad4f87fd47
children aeeddb9ce9c9
files ui.c
diffstat 1 files changed, 84 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/ui.c	Mon Mar 09 20:10:00 2020 +0100
+++ b/ui.c	Tue Mar 10 20:00:00 2020 +0100
@@ -509,18 +509,18 @@
 	else
 		bg = 0;
 
-	return COLOR_PAIR((64 + 1) + fg + (bg * SIZE(irc_colors)));
+	return (64 + 1) + fg + (bg * SIZE(irc_colors));
 
 }
 
-static int
-view_apply_color(const char **p)
+static short
+view_get_color(const wchar_t **p)
 {
 	assert(*p && **p == 0x03);
 
 	int foreground = 0;
 	int background = -1;
-	int attrs;
+	short color;
 
 	/*
 	 * Three possibilities:
@@ -531,24 +531,90 @@
 	 */
 	(*p)++;
 
-	switch (sscanf(*p, "%2d,%2d", &foreground, &background)) {
+	switch (swscanf(*p, L"%2d,%2d", &foreground, &background)) {
 	case 1:
 		/* Only foreground. */
-		attrs = view_pair(foreground, background);
+		color = view_pair(foreground, background);
 		(*p) += (foreground >= 10) ? 2 : 1;
 		break;
 	case 2:
-		attrs = view_pair(foreground, background);
+		color = view_pair(foreground, background);
 		(*p) += (foreground >= 10) ? 2 : 1;
 		(*p) += 1;
 		(*p) += (background >= 10) ? 2 : 1;
 		break;
 	default:
-		attrs = 0;
+		color = 0;
 		break;
 	}
 
-	return attrs;
+	return color;
+}
+
+static wchar_t *
+view_convert(const char *s)
+{
+	assert(s);
+
+	wchar_t *wstr;
+	size_t length;
+
+	/* Determine the length required. */
+	if ((length = mbstowcs(NULL, s, 0)) == (size_t)-1)
+		return NULL;
+
+	wstr = ecalloc(sizeof (wchar_t), length + 1);
+	mbstowcs(wstr, s, length);
+
+	return wstr;
+}
+
+static void
+view_output_char(wchar_t ch, attr_t attrs, short color)
+{
+	WINDOW *f = widgets[UI_ELT_VIEW].frame;
+	cchar_t cc = { 0 };
+
+	setcchar(&cc, (const wchar_t []) { ch, 0 }, attrs, color, NULL);
+	wadd_wch(f, &cc);
+}
+
+static void
+view_output_line(const wchar_t *line)
+{
+	assert(line);
+
+	attr_t attrs = A_NORMAL;
+	short color = 0;
+
+	for (const wchar_t *p = line; *p; ++p) {
+		switch (*p) {
+		case 0x02: /* BOLD */
+			attrs ^= A_BOLD;
+			break;
+		case 0x1d: /* ITALICS */
+			attrs ^= A_ITALIC;
+			break;
+		case 0x1f: /* UNDERLINE */
+			attrs ^= A_UNDERLINE;
+			break;
+		case 0x16: /* REVERSE */
+			attrs ^= A_REVERSE;
+			break;
+		case 0x0f: /* RESET */
+			attrs = 0;
+			color = 0;
+			break;
+		case 0x03: /* COLORS */
+			color = view_get_color(&p);
+			/* Fallthrough. */
+		default:
+			view_output_char(*p, attrs, color);
+			break;
+		}
+	}
+
+	view_output_char('\n', A_NORMAL, 0);
 }
 
 static void
@@ -566,35 +632,17 @@
 	wmove(f, 0, 0);
 
 	for (size_t i = 0; i < j->linesz; ++i) {
-		int attrs = 0;
+		wchar_t *line;
 
-		for (const char *p = j->lines[i]; *p; ++p) {
-			switch (*p) {
-			case 0x02: /* BOLD */
-				attrs ^= A_BOLD;
-				break;
-			case 0x1d: /* ITALICS */
-				attrs ^= A_ITALIC;
-				break;
-			case 0x1f: /* UNDERLINE */
-				attrs ^= A_UNDERLINE;
-				break;
-			case 0x16: /* REVERSE */
-				attrs ^= A_REVERSE;
-				break;
-			case 0x0f: /* RESET */
-				attrs = 0;
-				break;
-			case 0x03: /* COLORS */
-				attrs |= view_apply_color(&p);
-				/* Fallthrough. */
-			default:
-				waddch(f, *p | attrs);
-				break;
-			}
+		/*
+		 * It's easier to convert the line into a wide-string as
+		 * outputing individual UTF-8 characters with (w)addch could
+		 * add some video attributes which we want to avoid.
+		 */
+		if ((line = view_convert(j->lines[i]))) {
+			view_output_line(line);
+			free(line);
 		}
-
-		waddch(f, '\n');
 	}
 
 	prefresh(f, 0, 0, 1, x, h, COLS);