diff options
author | Matthias Clasen <mclasen@redhat.com> | 2014-12-04 00:08:30 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2014-12-04 00:09:44 -0500 |
commit | 3d4bcf55a520bd77fda4de4ef824eb9485b24d58 (patch) | |
tree | e107874f646400123aa4813ef1dededeef653e5e /gtk/gtktextbuffer.c | |
parent | d184088cae96e0d05f96c923167b260e7832d82e (diff) | |
download | gtk+-3d4bcf55a520bd77fda4de4ef824eb9485b24d58.tar.gz |
Allow inserting Pango markup in text buffers
This has been a very long-standing feature request.
https://bugzilla.gnome.org/show_bug.cgi?id=59390
Diffstat (limited to 'gtk/gtktextbuffer.c')
-rw-r--r-- | gtk/gtktextbuffer.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 65dfd8550f..a4db3533a7 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -4720,3 +4720,182 @@ _gtk_text_buffer_get_text_after (GtkTextBuffer *buffer, break; } } + +static GtkTextTag * +get_tag_for_attributes (PangoAttrIterator *iter) +{ + PangoAttribute *attr; + GtkTextTag *tag; + + tag = gtk_text_tag_new (NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE); + if (attr) + g_object_set (tag, "language", pango_language_to_string (((PangoAttrLanguage*)attr)->value), NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY); + if (attr) + g_object_set (tag, "family", ((PangoAttrString*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_STYLE); + if (attr) + g_object_set (tag, "style", ((PangoAttrInt*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT); + if (attr) + g_object_set (tag, "weight", ((PangoAttrInt*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_VARIANT); + if (attr) + g_object_set (tag, "variant", ((PangoAttrInt*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRETCH); + if (attr) + g_object_set (tag, "stretch", ((PangoAttrInt*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_SIZE); + if (attr) + g_object_set (tag, "size", ((PangoAttrInt*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_FONT_DESC); + if (attr) + g_object_set (tag, "font-desc", ((PangoAttrFontDesc*)attr)->desc, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND); + if (attr) + { + PangoColor *color; + GdkRGBA rgba; + + color = &((PangoAttrColor*)attr)->color; + rgba.red = color->red / 65535.; + rgba.green = color->green / 65535.; + rgba.blue = color->blue / 65535.; + rgba.alpha = 1.; + g_object_set (tag, "foreground-rgba", &rgba, NULL); + }; + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_BACKGROUND); + if (attr) + { + PangoColor *color; + GdkRGBA rgba; + + color = &((PangoAttrColor*)attr)->color; + rgba.red = color->red / 65535.; + rgba.green = color->green / 65535.; + rgba.blue = color->blue / 65535.; + rgba.alpha = 1.; + g_object_set (tag, "background-rgba", &rgba, NULL); + }; + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE); + if (attr) + g_object_set (tag, "underline", ((PangoAttrInt*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH); + if (attr) + g_object_set (tag, "strikethrough", (gboolean) (((PangoAttrInt*)attr)->value != 0), NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_RISE); + if (attr) + g_object_set (tag, "rise", ((PangoAttrInt*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_SCALE); + if (attr) + g_object_set (tag, "scale", ((PangoAttrFloat*)attr)->value, NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_FALLBACK); + if (attr) + g_object_set (tag, "fallback", (gboolean) (((PangoAttrInt*)attr)->value != 0), NULL); + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_LETTER_SPACING); + if (attr) + g_object_set (tag, "letter-spacing", ((PangoAttrInt*)attr)->value, NULL); + + return tag; +} + +static void +gtk_text_buffer_insert_with_attributes (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + PangoAttrList *attributes) +{ + GtkTextMark *mark; + PangoAttrIterator *attr; + GtkTextTagTable *tags; + + g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); + + if (!attributes) + { + gtk_text_buffer_insert (buffer, iter, text, -1); + return; + } + + /* create mark with right gravity */ + mark = gtk_text_buffer_create_mark (buffer, NULL, iter, FALSE); + attr = pango_attr_list_get_iterator (attributes); + tags = gtk_text_buffer_get_tag_table (buffer); + + do + { + GtkTextTag *tag; + gint start, end; + + pango_attr_iterator_range (attr, &start, &end); + + if (end == G_MAXINT) /* last chunk */ + end = start - 1; /* resulting in -1 to be passed to _insert */ + + tag = get_tag_for_attributes (attr); + gtk_text_tag_table_add (tags, tag); + + gtk_text_buffer_insert_with_tags (buffer, iter, text + start, end - start, tag, NULL); + + gtk_text_buffer_get_iter_at_mark (buffer, iter, mark); + } + while (pango_attr_iterator_next (attr)); + + gtk_text_buffer_delete_mark (buffer, mark); + pango_attr_iterator_destroy (attr); +} + +/** + * gtk_text_buffer_insert_markup: + * @buffer: a #GtkTextBuffer + * @iter: location to insert the markup + * @markup: a nul-terminated UTF-8 string containing [Pango markup][PangoMarkupFormat] + * @len: length of @markup in bytes, or -1 + * + * Inserts the text in @markup at position @iter. @markup will be inserted + * in its entirety and must be nul-terminated and valid UTF-8. Emits the + * #GtkTextBuffer::insert-text signal, possibly multiple times; insertion + * actually occurs in the default handler for the signal. @iter will point + * to the end of the inserted text on return. + * + * Since: 3.16 + */ +void +gtk_text_buffer_insert_markup (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *markup, + gint len) +{ + PangoAttrList *attributes; + gchar *text; + GError *error = NULL; + + if (!pango_parse_markup (markup, len, 0, &attributes, &text, NULL, &error)) + { + g_warning ("Invalid markup string: %s", error->message); + g_error_free (error); + return; + } + + gtk_text_buffer_insert_with_attributes (buffer, iter, text, attributes); + + pango_attr_list_unref (attributes); + g_free (text); +} |