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

View File

@@ -259,6 +259,37 @@ nmt_newt_locale_from_utf8 (const char *str_utf8)
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:
* @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_from_utf8 (const char *str_utf8);
int nmt_newt_text_width (const char *str);
void nmt_newt_message_dialog (const char *message,
...);
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) {
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",
active_col,
nmtconn->name,
(int)(max_width - g_utf8_strlen (nmtconn->name, -1)), "",
(int)(max_width - nmt_newt_text_width (nmtconn->name)), "",
strength_col);
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);
NmtNewtWidget *header, *empty;
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;
header = nmt_newt_grid_new ();
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,
"text", text,
"style", NMT_NEWT_LABEL_PLAIN,
@@ -230,7 +230,7 @@ nmt_route_table_init (NmtRouteTable *table)
"text", text,
"style", NMT_NEWT_LABEL_PLAIN,
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);
text = _("Metric");
@@ -238,18 +238,18 @@ nmt_route_table_init (NmtRouteTable *table)
"text", text,
"style", NMT_NEWT_LABEL_PLAIN,
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);
priv->ip_entry_width = MAX (20, MAX (dest_prefix_len, next_hop_len));
priv->metric_entry_width = MAX (7, metric_len);
priv->ip_entry_width = MAX (20, MAX (dest_prefix_width, next_hop_width));
priv->metric_entry_width = MAX (7, metric_width);
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,
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,
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);

View File

@@ -193,15 +193,15 @@ listbox_active_changed (GObject *object,
gboolean has_selection;
if (G_UNLIKELY (activate == NULL)) {
int activate_len, deactivate_len;
int activate_width, deactivate_width;
activate = _("Activate");
activate_len = g_utf8_strlen (activate, -1);
activate_width = nmt_newt_text_width (activate);
deactivate = _("Deactivate");
deactivate_len = g_utf8_strlen (deactivate, -1);
deactivate_width = nmt_newt_text_width (deactivate);
activate_padding = MAX (0, deactivate_len - activate_len);
deactivate_padding = MAX (0, activate_len - deactivate_len);
activate_padding = MAX (0, deactivate_width - activate_width);
deactivate_padding = MAX (0, activate_width - deactivate_width);
}
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);
for (i = 0; i < num_subprograms; i++) {
g_printerr ("%*s nmtui %s [%s]\n",
(int) g_utf8_strlen (usage, -1), " ",
nmt_newt_text_width (usage), " ",
subprograms[i].name,
_(subprograms[i].arg));
}