[gtk/wip/baedert/for-master: 25/39] label: Set underline text and markup in one step
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/baedert/for-master: 25/39] label: Set underline text and markup in one step
- Date: Fri, 17 Apr 2020 13:23:40 +0000 (UTC)
commit f0b33cdc535e378c12a97d0158115149f5f541d3
Author: Timm Bäder <mail baedert org>
Date: Sun Apr 12 19:54:20 2020 +0200
label: Set underline text and markup in one step
Try to unify the way we parse the mnemonic character
gtk/gtklabel.c | 364 ++++++++++++++++++++-------------------------------------
1 file changed, 129 insertions(+), 235 deletions(-)
---
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index a4c9a6b707..4684cf3542 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -465,8 +465,6 @@ static gboolean gtk_label_set_use_markup_internal (GtkLabel *label,
gboolean val);
static gboolean gtk_label_set_use_underline_internal (GtkLabel *label,
gboolean val);
-static void gtk_label_set_uline_text_internal (GtkLabel *label,
- const gchar *str);
static void gtk_label_set_markup_internal (GtkLabel *label,
const gchar *str,
gboolean with_uline);
@@ -510,11 +508,6 @@ static void gtk_label_buildable_custom_finished (GtkBuildable *builda
GObject *child,
const gchar *tagname,
gpointer user_data);
-static gboolean separate_uline_pattern (const gchar *str,
- guint *accel_key,
- gchar **new_str,
- gchar **pattern);
-
/* For selectable labels: */
static void gtk_label_move_cursor (GtkLabel *label,
@@ -1457,7 +1450,6 @@ label_mnemonics_visible_changed (GtkWidget *widget,
{
gboolean visible;
- g_message (__FUNCTION__);
g_object_get (widget, "mnemonics-visible", &visible, NULL);
_gtk_label_mnemonics_visible_apply_recursively (widget, visible);
}
@@ -1815,10 +1807,8 @@ gtk_label_recalculate (GtkLabel *label)
gtk_label_clear_layout (label);
gtk_label_clear_select_info (label);
- if (priv->use_markup)
+ if (priv->use_markup || priv->use_underline)
gtk_label_set_markup_internal (label, priv->label, priv->use_underline);
- else if (priv->use_underline)
- gtk_label_set_uline_text_internal (label, priv->label);
else
{
g_clear_pointer (&priv->markup_attrs, pango_attr_list_unref);
@@ -2264,6 +2254,79 @@ gtk_label_ensure_has_tooltip (GtkLabel *label)
gtk_widget_set_has_tooltip (GTK_WIDGET (label), has_tooltip);
}
+/* Reads @text and extracts the accel key, if any.
+ * @new_text will be set to the given text with the first _ removed.
+ *
+ * Returned will be the one underline attribute used for the mnemonic
+ * */
+static void
+extract_mnemonic_keyval (const char *text,
+ guint *out_accel_key,
+ char **out_new_text,
+ PangoAttribute **out_mnemonic_attribute)
+{
+ const gsize text_len = strlen (text);
+ gunichar c;
+ const char *p;
+
+ p = text;
+ for (;;)
+ {
+ const char *_index;
+
+ c = g_utf8_get_char (p);
+
+ if (c == '\0')
+ break;
+
+ if (c != '_')
+ {
+ p = g_utf8_next_char (p);
+ continue;
+ }
+
+ _index = p;
+
+ p = g_utf8_next_char (p);
+ c = g_utf8_get_char (p);
+
+ if (c != '_' && c != '0')
+ {
+ const gsize byte_index = p - text - 1; /* Of the _ */
+
+ /* c is the accel key */
+ if (out_accel_key)
+ *out_accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
+ if (out_new_text)
+ {
+ *out_new_text = g_malloc (text_len);
+ memcpy (*out_new_text, text, byte_index);
+ memcpy (*out_new_text + byte_index, p, text_len - byte_index);
+ }
+
+ if (out_mnemonic_attribute)
+ {
+ PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
+ attr->start_index = _index - text;
+ attr->end_index = p - text;
+ *out_mnemonic_attribute = attr;
+ }
+
+ return;
+ }
+
+ p = g_utf8_next_char (p);
+ }
+
+ /* No accel key found */
+ if (out_accel_key)
+ *out_accel_key = GDK_KEY_VoidSymbol;
+ if (out_new_text)
+ *out_new_text = NULL;
+ if (out_mnemonic_attribute)
+ *out_mnemonic_attribute = NULL;
+}
+
static void
gtk_label_set_markup_internal (GtkLabel *label,
const gchar *str,
@@ -2273,20 +2336,13 @@ gtk_label_set_markup_internal (GtkLabel *label,
gchar *text = NULL;
GError *error = NULL;
PangoAttrList *attrs = NULL;
- gunichar accel_char = 0;
gchar *str_for_display = NULL;
- gchar *str_for_accel = NULL;
GtkLabelLink *links = NULL;
guint n_links = 0;
+ PangoAttribute *mnemonic_attr = NULL;
if (!parse_uri_markup (label, str, &str_for_display, &links, &n_links, &error))
- {
- g_warning ("Failed to set text '%s' from markup due to error parsing markup: %s",
- str, error->message);
- g_error_free (error);
- return;
- }
-
+ goto error_set;
if (links)
{
@@ -2298,68 +2354,57 @@ gtk_label_set_markup_internal (GtkLabel *label,
gtk_widget_add_css_class (GTK_WIDGET (label), "link");
}
- if (with_uline)
- {
- gboolean enable_mnemonics = TRUE;
+ if (!with_uline)
+ {
+no_uline:
+ /* Extract the text to display */
+ if (!pango_parse_markup (str_for_display, -1, 0, &attrs, &text, NULL, &error))
+ goto error_set;
+ }
+ else /* Underline AND markup is a little more complicated... */
+ {
+ char *new_text = NULL;
+ guint accel_keyval;
gboolean auto_mnemonics = TRUE;
+ gboolean do_mnemonics = priv->mnemonics_visible &&
+ (!auto_mnemonics || gtk_widget_is_sensitive (GTK_WIDGET (label))) &&
+ (!priv->mnemonic_widget || gtk_widget_is_sensitive (priv->mnemonic_widget));
- str_for_accel = g_strdup (str_for_display);
+ /* Remove the mnemonic underline */
+ extract_mnemonic_keyval (str_for_display,
+ &accel_keyval,
+ &new_text,
+ NULL);
+ if (!new_text) /* No underline found anyway */
+ goto no_uline;
- if (!(enable_mnemonics && priv->mnemonics_visible &&
- (!auto_mnemonics ||
- (gtk_widget_is_sensitive (GTK_WIDGET (label)) &&
- (!priv->mnemonic_widget ||
- gtk_widget_is_sensitive (priv->mnemonic_widget))))))
- {
- gchar *tmp;
- gchar *pattern;
- guint key;
+ priv->mnemonic_keyval = accel_keyval;
- if (separate_uline_pattern (str_for_display, &key, &tmp, &pattern))
- {
- g_free (str_for_display);
- str_for_display = tmp;
- g_free (pattern);
- }
- }
- }
+ /* Extract the text to display */
+ if (!pango_parse_markup (new_text, -1, '_', &attrs, &text, NULL, &error))
+ goto error_set;
- /* Extract the text to display */
- if (!pango_parse_markup (str_for_display,
- -1,
- with_uline ? '_' : 0,
- &attrs,
- &text,
- NULL,
- &error))
- {
- g_warning ("Failed to set text '%s' from markup due to error parsing markup: %s",
- str_for_display, error->message);
- g_free (str_for_display);
- g_free (str_for_accel);
- g_error_free (error);
- return;
- }
+ if (do_mnemonics)
+ {
+ /* text is now the final text, but we need to parse str_for_display once again
+ * *with* the mnemonic underline so we can remove the markup tags and get the
+ * proper attribute indices */
+ char *text_for_accel;
+
+ if (!pango_parse_markup (str_for_display, -1, 0, NULL, &text_for_accel, NULL, &error))
+ goto error_set;
+
+ extract_mnemonic_keyval (text_for_accel,
+ NULL,
+ NULL,
+ &mnemonic_attr);
+ g_free (text_for_accel);
+ }
- /* Extract the accelerator character */
- if (with_uline && !pango_parse_markup (str_for_accel,
- -1,
- '_',
- NULL,
- NULL,
- &accel_char,
- &error))
- {
- g_warning ("Failed to set text from markup due to error parsing markup: %s",
- error->message);
- g_free (str_for_display);
- g_free (str_for_accel);
- g_error_free (error);
- return;
- }
+ g_free (new_text);
+ }
g_free (str_for_display);
- g_free (str_for_accel);
if (text)
gtk_label_set_text_internal (label, text);
@@ -2368,12 +2413,18 @@ gtk_label_set_markup_internal (GtkLabel *label,
{
g_clear_pointer (&priv->markup_attrs, pango_attr_list_unref);
priv->markup_attrs = attrs;
+
+ if (mnemonic_attr)
+ pango_attr_list_insert_before (priv->markup_attrs, mnemonic_attr);
}
- if (accel_char != 0)
- priv->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
- else
- priv->mnemonic_keyval = GDK_KEY_VoidSymbol;
+ return;
+
+error_set:
+ g_warning ("Failed to set text '%s' from markup due to error parsing markup: %s",
+ str, error->message);
+ g_error_free (error);
+
}
/**
@@ -2478,47 +2529,6 @@ gtk_label_get_text (GtkLabel *label)
return priv->text;
}
-static PangoAttrList *
-gtk_label_pattern_to_attrs (GtkLabel *label,
- const gchar *pattern)
-{
- GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
- const char *start;
- const char *p = priv->text;
- const char *q = pattern;
- PangoAttrList *attrs;
-
- attrs = pango_attr_list_new ();
-
- while (1)
- {
- while (*p && *q && *q != '_')
- {
- p = g_utf8_next_char (p);
- q++;
- }
- start = p;
- while (*p && *q && *q == '_')
- {
- p = g_utf8_next_char (p);
- q++;
- }
-
- if (p > start)
- {
- PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
- attr->start_index = start - priv->text;
- attr->end_index = p - priv->text;
-
- pango_attr_list_insert (attrs, attr);
- }
- else
- break;
- }
-
- return attrs;
-}
-
/**
* gtk_label_set_justify:
* @label: a #GtkLabel
@@ -3616,122 +3626,6 @@ gtk_label_snapshot (GtkWidget *widget,
}
}
-static gboolean
-separate_uline_pattern (const gchar *str,
- guint *accel_key,
- gchar **new_str,
- gchar **pattern)
-{
- gboolean underscore;
- const gchar *src;
- gchar *dest;
- gchar *pattern_dest;
-
- *accel_key = GDK_KEY_VoidSymbol;
- *new_str = g_new (gchar, strlen (str) + 1);
- *pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
-
- underscore = FALSE;
-
- src = str;
- dest = *new_str;
- pattern_dest = *pattern;
-
- while (*src)
- {
- gunichar c;
- const gchar *next_src;
-
- c = g_utf8_get_char (src);
- if (c == (gunichar)-1)
- {
- g_warning ("Invalid input string");
- g_free (*new_str);
- g_free (*pattern);
-
- return FALSE;
- }
- next_src = g_utf8_next_char (src);
-
- if (underscore)
- {
- if (c == '_')
- *pattern_dest++ = ' ';
- else
- {
- *pattern_dest++ = '_';
- if (*accel_key == GDK_KEY_VoidSymbol)
- *accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
- }
-
- while (src < next_src)
- *dest++ = *src++;
-
- underscore = FALSE;
- }
- else
- {
- if (c == '_')
- {
- underscore = TRUE;
- src = next_src;
- }
- else
- {
- while (src < next_src)
- *dest++ = *src++;
-
- *pattern_dest++ = ' ';
- }
- }
- }
-
- *dest = 0;
- *pattern_dest = 0;
-
- return TRUE;
-}
-
-static void
-gtk_label_set_uline_text_internal (GtkLabel *label,
- const char *str)
-{
- GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
- guint accel_key = GDK_KEY_VoidSymbol;
- gboolean auto_mnemonics = TRUE;
- PangoAttrList *attrs;
- char *new_str;
- char *pattern;
-
- g_return_if_fail (GTK_IS_LABEL (label));
- g_return_if_fail (str != NULL);
-
- /* Split text into the base text and a separate pattern
- * of underscores.
- */
- if (!separate_uline_pattern (str, &accel_key, &new_str, &pattern))
- return;
-
- gtk_label_set_text_internal (label, new_str);
-
- if (priv->mnemonics_visible && pattern &&
- (!auto_mnemonics ||
- (gtk_widget_is_sensitive (GTK_WIDGET (label)) &&
- (!priv->mnemonic_widget ||
- gtk_widget_is_sensitive (priv->mnemonic_widget)))))
- attrs = gtk_label_pattern_to_attrs (label, pattern);
- else
- attrs = NULL;
-
- if (priv->markup_attrs)
- pango_attr_list_unref (priv->markup_attrs);
- priv->markup_attrs = attrs;
-
- priv->mnemonic_keyval = accel_key;
-
- g_free (pattern);
-}
-
/**
* gtk_label_set_text_with_mnemonic:
* @label: a #GtkLabel
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]