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:
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user