tui: add nmt_newt_text_width()

We were using g_utf8_strlen() to measure strings for layout, but that
counts combining marks too, and also fails to deal with "fullwidth"
(ie, double-width) CJK characters.

Add a new utility function to do a better job of this (based on code
from vte), and use it everywhere.
This commit is contained in:
Dan Winship
2014-01-06 13:34:30 -05:00
parent 1d40b9f872
commit 64cb43b3b2
7 changed files with 54 additions and 21 deletions

View File

@@ -95,7 +95,7 @@ nmt_newt_textbox_set_text (NmtNewtTextbox *textbox,
{ {
NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox);
char **lines; char **lines;
int i, len; int i, width;
if (!text) if (!text)
text = ""; text = "";
@@ -108,9 +108,9 @@ nmt_newt_textbox_set_text (NmtNewtTextbox *textbox,
priv->width = priv->height = 0; priv->width = priv->height = 0;
lines = g_strsplit (priv->text, "\n", -1); lines = g_strsplit (priv->text, "\n", -1);
for (i = 0; lines[i]; i++) { for (i = 0; lines[i]; i++) {
len = g_utf8_strlen (lines[i], -1); width = nmt_newt_text_width (lines[i]);
if (len > priv->width) if (width > priv->width)
priv->width = len; priv->width = width;
} }
g_free (lines); g_free (lines);
priv->height = MIN (i, 1); priv->height = MIN (i, 1);

View File

@@ -259,6 +259,37 @@ nmt_newt_locale_from_utf8 (const char *str_utf8)
return str_lc; return str_lc;
} }
/**
* nmt_newt_text_width
* @str: a UTF-8 string
*
* Computes the width (in terminal columns) of @str.
*
* Returns: the width of @str
*/
int
nmt_newt_text_width (const char *str)
{
int width;
gunichar ch;
for (width = 0; *str; str = g_utf8_next_char (str)) {
ch = g_utf8_get_char (str);
/* Based on _vte_iso2022_unichar_width */
if (G_LIKELY (ch < 0x80))
width += 1;
else if (G_UNLIKELY (g_unichar_iszerowidth (ch)))
width += 0;
else if (G_UNLIKELY (g_unichar_iswide (ch)))
width += 2;
else
width += 1;
}
return width;
}
/** /**
* nmt_newt_edit_string: * nmt_newt_edit_string:
* @data: data to edit * @data: data to edit

View File

@@ -37,6 +37,8 @@ typedef enum {
char *nmt_newt_locale_to_utf8 (const char *str_lc); char *nmt_newt_locale_to_utf8 (const char *str_lc);
char *nmt_newt_locale_from_utf8 (const char *str_utf8); char *nmt_newt_locale_from_utf8 (const char *str_utf8);
int nmt_newt_text_width (const char *str);
void nmt_newt_message_dialog (const char *message, void nmt_newt_message_dialog (const char *message,
...); ...);
int nmt_newt_choice_dialog (const char *button1, int nmt_newt_choice_dialog (const char *button1,

View File

@@ -436,7 +436,7 @@ nmt_connect_connection_list_rebuild (NmtConnectConnectionList *list)
for (citer = nmtdev->conns; citer; citer = citer->next) { for (citer = nmtdev->conns; citer; citer = citer->next) {
nmtconn = citer->data; nmtconn = citer->data;
max_width = MAX (max_width, g_utf8_strlen (nmtconn->name, -1)); max_width = MAX (max_width, nmt_newt_text_width (nmtconn->name));
} }
} }
@@ -477,7 +477,7 @@ nmt_connect_connection_list_rebuild (NmtConnectConnectionList *list)
row = g_strdup_printf ("%c %s%-*s%s", row = g_strdup_printf ("%c %s%-*s%s",
active_col, active_col,
nmtconn->name, nmtconn->name,
(int)(max_width - g_utf8_strlen (nmtconn->name, -1)), "", (int)(max_width - nmt_newt_text_width (nmtconn->name)), "",
strength_col); strength_col);
nmt_newt_listbox_append (listbox, row, nmtconn); nmt_newt_listbox_append (listbox, row, nmtconn);

View File

@@ -211,13 +211,13 @@ nmt_route_table_init (NmtRouteTable *table)
NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table); NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table);
NmtNewtWidget *header, *empty; NmtNewtWidget *header, *empty;
NmtNewtWidget *dest_prefix_label, *next_hop_label, *metric_label; NmtNewtWidget *dest_prefix_label, *next_hop_label, *metric_label;
int dest_prefix_len, next_hop_len, metric_len; int dest_prefix_width, next_hop_width, metric_width;
char *text; char *text;
header = nmt_newt_grid_new (); header = nmt_newt_grid_new ();
text = g_strdup_printf ("%s/%s", _("Destination"), _("Prefix")); text = g_strdup_printf ("%s/%s", _("Destination"), _("Prefix"));
dest_prefix_len = g_utf8_strlen (text, -1); dest_prefix_width = nmt_newt_text_width (text);
dest_prefix_label = g_object_new (NMT_TYPE_NEWT_LABEL, dest_prefix_label = g_object_new (NMT_TYPE_NEWT_LABEL,
"text", text, "text", text,
"style", NMT_NEWT_LABEL_PLAIN, "style", NMT_NEWT_LABEL_PLAIN,
@@ -230,7 +230,7 @@ nmt_route_table_init (NmtRouteTable *table)
"text", text, "text", text,
"style", NMT_NEWT_LABEL_PLAIN, "style", NMT_NEWT_LABEL_PLAIN,
NULL); NULL);
next_hop_len = g_utf8_strlen (text, -1); next_hop_width = nmt_newt_text_width (text);
nmt_newt_grid_add (NMT_NEWT_GRID (header), next_hop_label, 1, 0); nmt_newt_grid_add (NMT_NEWT_GRID (header), next_hop_label, 1, 0);
text = _("Metric"); text = _("Metric");
@@ -238,18 +238,18 @@ nmt_route_table_init (NmtRouteTable *table)
"text", text, "text", text,
"style", NMT_NEWT_LABEL_PLAIN, "style", NMT_NEWT_LABEL_PLAIN,
NULL); NULL);
metric_len = g_utf8_strlen (text, -1); metric_width = nmt_newt_text_width (text);
nmt_newt_grid_add (NMT_NEWT_GRID (header), metric_label, 2, 0); nmt_newt_grid_add (NMT_NEWT_GRID (header), metric_label, 2, 0);
priv->ip_entry_width = MAX (20, MAX (dest_prefix_len, next_hop_len)); priv->ip_entry_width = MAX (20, MAX (dest_prefix_width, next_hop_width));
priv->metric_entry_width = MAX (7, metric_len); priv->metric_entry_width = MAX (7, metric_width);
nmt_newt_widget_set_padding (dest_prefix_label, nmt_newt_widget_set_padding (dest_prefix_label,
0, 0, priv->ip_entry_width - dest_prefix_len, 0); 0, 0, priv->ip_entry_width - dest_prefix_width, 0);
nmt_newt_widget_set_padding (next_hop_label, nmt_newt_widget_set_padding (next_hop_label,
2, 0, priv->ip_entry_width - next_hop_len, 0); 2, 0, priv->ip_entry_width - next_hop_width, 0);
nmt_newt_widget_set_padding (metric_label, nmt_newt_widget_set_padding (metric_label,
2, 0, priv->metric_entry_width - metric_len, 0); 2, 0, priv->metric_entry_width - metric_width, 0);
nmt_newt_grid_add (NMT_NEWT_GRID (table), header, 0, 0); nmt_newt_grid_add (NMT_NEWT_GRID (table), header, 0, 0);

View File

@@ -193,15 +193,15 @@ listbox_active_changed (GObject *object,
gboolean has_selection; gboolean has_selection;
if (G_UNLIKELY (activate == NULL)) { if (G_UNLIKELY (activate == NULL)) {
int activate_len, deactivate_len; int activate_width, deactivate_width;
activate = _("Activate"); activate = _("Activate");
activate_len = g_utf8_strlen (activate, -1); activate_width = nmt_newt_text_width (activate);
deactivate = _("Deactivate"); deactivate = _("Deactivate");
deactivate_len = g_utf8_strlen (deactivate, -1); deactivate_width = nmt_newt_text_width (deactivate);
activate_padding = MAX (0, deactivate_len - activate_len); activate_padding = MAX (0, deactivate_width - activate_width);
deactivate_padding = MAX (0, activate_len - deactivate_len); deactivate_padding = MAX (0, activate_width - deactivate_width);
} }
has_selection = nmt_connect_connection_list_get_selection (list, NULL, NULL, NULL, &ac); has_selection = nmt_connect_connection_list_get_selection (list, NULL, NULL, NULL, &ac);

View File

@@ -164,7 +164,7 @@ usage (void)
g_printerr ("%s: nmtui\n", usage); g_printerr ("%s: nmtui\n", usage);
for (i = 0; i < num_subprograms; i++) { for (i = 0; i < num_subprograms; i++) {
g_printerr ("%*s nmtui %s [%s]\n", g_printerr ("%*s nmtui %s [%s]\n",
(int) g_utf8_strlen (usage, -1), " ", nmt_newt_text_width (usage), " ",
subprograms[i].name, subprograms[i].name,
_(subprograms[i].arg)); _(subprograms[i].arg));
} }