From cb8c07934ae4a4eec0ab60d44b60a05ead3a82a0 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Wed, 12 Feb 2020 18:59:54 +0100 Subject: [WIP] Add proper UTF-8 text-alignment support --- src/ctl.h | 2 +- src/interface.c | 110 +++++++++++++++++++++++++++++++++++++------------------- src/interface.h | 1 - 3 files changed, 74 insertions(+), 39 deletions(-) diff --git a/src/ctl.h b/src/ctl.h index e9ef304..90dce7f 100644 --- a/src/ctl.h +++ b/src/ctl.h @@ -28,7 +28,7 @@ struct context; struct vol_ctl { guint32 index; gchar *name; /* displayed name */ - gint indent; /* indentation when displayed */ + guint indent; /* indentation when displayed */ gboolean hide_index; pa_volume_t vol; // TOTO: exchange with the channel-list diff --git a/src/interface.c b/src/interface.c index 0ed84eb..8ae9494 100644 --- a/src/interface.c +++ b/src/interface.c @@ -18,11 +18,11 @@ */ #define _XOPEN_SOURCE 700 -#define NCURSES_WIDECHAR 1 #include #include #include +#include #include #include @@ -77,41 +77,43 @@ print_volume(struct interface *ifc, struct vol_ctl *ctl) ctl->mute ? 'M':' ', ifc->volume_bar_len, vol, ifc->volume_bar); } -static char * -ellipsize(char *str, size_t length) +static gchar * +str_middle_truncate (const gchar *string, guint truncate_length) { - char *trimmed; - size_t offset_start, offset_end; - - if (strlen(str) <= length) { - return g_strdup(str); + const gchar ellipsis[] = "…"; + glong ellipsis_length; + glong length; + glong num_left_chars; + glong num_right_chars; + g_autofree gchar *left_substring = NULL; + g_autofree gchar *right_substring = NULL; + + g_return_val_if_fail(string != NULL, NULL); + g_return_val_if_fail(truncate_length > 0, NULL); + + ellipsis_length = g_utf8_strlen(ellipsis, -1); + + /* Our ellipsis string + one character on each side. */ + if (truncate_length < ellipsis_length + 2) { + return g_strdup(string); } - /* TODO: currently required to normalize long size */ - length = length + 2; - - trimmed = g_new(char, length + 1); - - offset_start = length/2 - 2; - offset_end = length - offset_start - 3; + length = g_utf8_strlen(string, -1); - strncpy(trimmed, str, offset_start); + if (length <= truncate_length) { + return g_strdup(string); + } - /* - trimmed[offset_start] = '.'; - trimmed[offset_start+1] = '.'; - trimmed[offset_start+2] = '.'; - */ + num_left_chars = (truncate_length - ellipsis_length) / 2; + num_right_chars = truncate_length - num_left_chars - ellipsis_length; - // Unicode '…' character - trimmed[offset_start] = (char)0xe2; - trimmed[offset_start+1] = (char)0x80; - trimmed[offset_start+2] = (char)0xa6; + g_assert (num_left_chars > 0); + g_assert (num_right_chars > 0); - strncpy(&trimmed[offset_start+3], &str[strlen(str) - offset_end], offset_end); - trimmed[length] = '\0'; + left_substring = g_utf8_substring(string, 0, num_left_chars); + right_substring = g_utf8_substring(string, length - num_right_chars, length); - return trimmed; + return g_strconcat(left_substring, ellipsis, right_substring, NULL); } static void @@ -120,7 +122,8 @@ print_vol_ctl(gpointer data, gpointer user_data) struct vol_ctl *ctl = data; struct interface *ifc = user_data; gint x, y; - size_t max_x, max_y, name_len; + guint i; + size_t max_x, max_y, max_name_len, name_len; char *name; (void) max_y; @@ -129,15 +132,48 @@ print_vol_ctl(gpointer data, gpointer user_data) wattron(ifc->menu_win, A_REVERSE); getmaxyx(ifc->menu_win, max_y, max_x); - name_len = (ifc->max_name_len > max_x / 2 ) ? max_x / 5 * 2 : ifc->max_name_len; + max_name_len = (ifc->max_name_len > max_x / 2 ) ? max_x / 5 * 2 : ifc->max_name_len; - if (!ctl->hide_index) + if (!ctl->hide_index) { wprintw(ifc->menu_win, "%2u ", ctl->index); - name = ellipsize(ctl->name, name_len); - wprintw(ifc->menu_win, "%*s%-*s", - ctl->indent + (ctl->hide_index ? 2+1 : 0), "", - name_len - ctl->indent, name); - g_free(name); + } else { + // Add padding instead of the (hidden) index + for (i = 0; i < (2+1); ++i) { + waddch(ifc->menu_win, ' '); + } + } + //name = ellipsize(ctl->name, name_len); + name = str_middle_truncate(ctl->name, max_name_len - ctl->indent); + if (name) { + for (i = 0; i < ctl->indent; ++i) { + waddch(ifc->menu_win, ' '); + } + name_len = g_utf8_strlen(name, -1); +#if 0 + wchar_t *wname = g_new(wchar_t, name_len + 1); + gint count = mbstowcs(wname, name, name_len + 1); + waddnwstr(ifc->menu_win, wname, count); + g_free(wname); +#else + // Note: This is supoosed to be non portable + // Quote from https://stackoverflow.com/a/30835920/4223467 + // ncurses differs from X/Open curses by allowing multibyte characters + // to be added via the waddstr (and waddch) interfaces. Actually this would + // be the "ncursesw" library (the "ncurses" library does 8-bit encodings). + waddstr(ifc->menu_win, name); + +#endif + + // Add padding + for (i = 0; i < max_name_len - name_len - ctl->indent; ++i) { + waddch(ifc->menu_win, ' '); + } + + //wprintw(ifc->menu_win, "%-*s", + // max_name_len - ctl->indent, name); + + g_free(name); + } if (ctl == ifc->current_ctl) wattroff(ifc->menu_win, A_REVERSE); @@ -155,7 +191,7 @@ max_name_len_helper(gpointer data, gpointer user_data) struct interface *ifc = user_data; guint len; - len = ctl->indent + strlen(ctl->name); + len = ctl->indent + g_utf8_strlen(ctl->name, -1); if (len > ifc->max_name_len) ifc->max_name_len = len; diff --git a/src/interface.h b/src/interface.h index 1e84a2b..b696526 100644 --- a/src/interface.h +++ b/src/interface.h @@ -21,7 +21,6 @@ #define INTERFACE_H #define _XOPEN_SOURCE 700 -#define NCURSES_WIDECHAR 1 #include #include -- cgit