mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
Merge branch 'text-anchor-replacement-char' into 'main'
textchildanchor: allow to specify replacement character See merge request GNOME/gtk!4213
This commit is contained in:
commit
d2bda8ea77
@ -7,7 +7,8 @@
|
||||
* shows.
|
||||
*
|
||||
* We also demonstrate adding other things to a text view, such as
|
||||
* clickable icons.
|
||||
* clickable icons and widgets which can also replace a character
|
||||
* (try copying the ghost text).
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@ -113,7 +114,12 @@ show_page (GtkTextView *text_view,
|
||||
gtk_level_bar_set_value (GTK_LEVEL_BAR (child), 50);
|
||||
gtk_widget_set_size_request (child, 100, -1);
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
gtk_text_buffer_insert (buffer, &iter, ".", -1);
|
||||
gtk_text_buffer_insert (buffer, &iter, " and labels with ", -1);
|
||||
anchor = gtk_text_child_anchor_new_with_replacement ("👻");
|
||||
gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
|
||||
child = gtk_label_new ("ghost");
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
gtk_text_buffer_insert (buffer, &iter, " text.", -1);
|
||||
}
|
||||
else if (page == 2)
|
||||
{
|
||||
|
@ -2362,8 +2362,7 @@ copy_segment (GString *string,
|
||||
|
||||
/* printf (" :%s\n", string->str); */
|
||||
}
|
||||
else if (seg->type == >k_text_paintable_type ||
|
||||
seg->type == >k_text_child_type)
|
||||
else if (seg->type == >k_text_paintable_type)
|
||||
{
|
||||
gboolean copy = TRUE;
|
||||
|
||||
@ -2382,7 +2381,27 @@ copy_segment (GString *string,
|
||||
g_string_append_len (string,
|
||||
_gtk_text_unknown_char_utf8,
|
||||
GTK_TEXT_UNKNOWN_CHAR_UTF8_LEN);
|
||||
}
|
||||
}
|
||||
else if (seg->type == >k_text_child_type)
|
||||
{
|
||||
gboolean copy = TRUE;
|
||||
if (!include_nonchars &&
|
||||
g_strcmp0 (_gtk_text_unknown_char_utf8, seg->body.child.obj->chars) == 0)
|
||||
{
|
||||
copy = FALSE;
|
||||
}
|
||||
else if (!include_hidden &&
|
||||
_gtk_text_btree_char_is_invisible (start))
|
||||
{
|
||||
copy = FALSE;
|
||||
}
|
||||
|
||||
if (copy)
|
||||
{
|
||||
g_string_append_len (string,
|
||||
seg->body.child.obj->chars,
|
||||
seg->byte_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7121,6 +7140,12 @@ _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent)
|
||||
printf ("%s chars '%s'...\n", spaces, str);
|
||||
g_free (str);
|
||||
}
|
||||
else if (seg->type == >k_text_child_type)
|
||||
{
|
||||
char *str = g_strndup (seg->body.child.obj->chars, seg->byte_count);
|
||||
printf ("%s child '%s'...\n", spaces, str);
|
||||
g_free (str);
|
||||
}
|
||||
else if (seg->type == >k_text_right_mark_type)
|
||||
{
|
||||
printf ("%s right mark '%s' visible: %d\n",
|
||||
@ -7223,6 +7248,12 @@ _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
|
||||
printf (" '%s'\n", str);
|
||||
g_free (str);
|
||||
}
|
||||
else if (seg->type == >k_text_child_type)
|
||||
{
|
||||
char *str = g_strndup (seg->body.child.obj->chars, seg->byte_count);
|
||||
printf (" '%s'\n", str);
|
||||
g_free (str);
|
||||
}
|
||||
else if (seg->type == >k_text_right_mark_type)
|
||||
{
|
||||
printf (" right mark '%s' visible: %d not_deleteable: %d\n",
|
||||
|
@ -267,9 +267,6 @@ child_segment_check_func (GtkTextLineSegment *seg,
|
||||
if (seg->next == NULL)
|
||||
g_error ("child segment is the last segment in a line");
|
||||
|
||||
if (seg->byte_count != GTK_TEXT_UNKNOWN_CHAR_UTF8_LEN)
|
||||
g_error ("child segment has byte count of %d", seg->byte_count);
|
||||
|
||||
if (seg->char_count != 1)
|
||||
g_error ("child segment has char count of %d", seg->char_count);
|
||||
}
|
||||
@ -301,11 +298,8 @@ _gtk_widget_segment_new (GtkTextChildAnchor *anchor)
|
||||
|
||||
seg->next = NULL;
|
||||
|
||||
/* We convert to the 0xFFFC "unknown character",
|
||||
* a 3-byte sequence in UTF-8.
|
||||
*/
|
||||
seg->byte_count = GTK_TEXT_UNKNOWN_CHAR_UTF8_LEN;
|
||||
seg->char_count = 1;
|
||||
seg->byte_count = strlen (anchor->chars);
|
||||
seg->char_count = g_utf8_strlen (anchor->chars, seg->byte_count);
|
||||
|
||||
seg->body.child.obj = anchor;
|
||||
seg->body.child.obj->segment = seg;
|
||||
@ -410,7 +404,28 @@ gtk_text_child_anchor_class_init (GtkTextChildAnchorClass *klass)
|
||||
GtkTextChildAnchor*
|
||||
gtk_text_child_anchor_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_TEXT_CHILD_ANCHOR, NULL);
|
||||
return gtk_text_child_anchor_new_with_replacement (_gtk_text_unknown_char_utf8);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_child_anchor_new_with_replacement:
|
||||
*
|
||||
* Creates a new `GtkTextChildAnchor` with the given replacement character.
|
||||
*
|
||||
* Usually you would then insert it into a `GtkTextBuffer` with
|
||||
* [method@Gtk.TextBuffer.insert_child_anchor].
|
||||
*
|
||||
* Returns: a new `GtkTextChildAnchor`
|
||||
**/
|
||||
GtkTextChildAnchor *
|
||||
gtk_text_child_anchor_new_with_replacement (const char *replacement_character)
|
||||
{
|
||||
/* only a single character can be set as replacement */
|
||||
g_return_val_if_fail (g_utf8_strlen (replacement_character, -1) == 1, NULL);
|
||||
|
||||
GtkTextChildAnchor *anchor = g_object_new (GTK_TYPE_TEXT_CHILD_ANCHOR, NULL);
|
||||
anchor->chars = g_strdup (replacement_character);
|
||||
return anchor;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -60,6 +60,7 @@ struct _GtkTextChildAnchor
|
||||
|
||||
/*< private >*/
|
||||
gpointer segment;
|
||||
char *chars; /* replacement character */
|
||||
};
|
||||
|
||||
struct _GtkTextChildAnchorClass
|
||||
@ -74,16 +75,19 @@ struct _GtkTextChildAnchorClass
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_text_child_anchor_get_type (void) G_GNUC_CONST;
|
||||
GType gtk_text_child_anchor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkTextChildAnchor* gtk_text_child_anchor_new (void);
|
||||
GtkTextChildAnchor *gtk_text_child_anchor_new (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GtkTextChildAnchor *gtk_text_child_anchor_new_with_replacement (const char *character);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget ** gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor,
|
||||
guint *out_len);
|
||||
GtkWidget **gtk_text_child_anchor_get_widgets (GtkTextChildAnchor *anchor,
|
||||
guint *out_len);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor);
|
||||
gboolean gtk_text_child_anchor_get_deleted (GtkTextChildAnchor *anchor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -892,6 +892,10 @@ gtk_text_iter_get_char (const GtkTextIter *iter)
|
||||
return g_utf8_get_char (real->segment->body.chars +
|
||||
real->segment_byte_offset);
|
||||
}
|
||||
else if (real->segment->type == >k_text_child_type)
|
||||
{
|
||||
return g_utf8_get_char (real->segment->body.child.obj->chars);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unicode "unknown character" 0xFFFC */
|
||||
|
@ -2470,7 +2470,7 @@ gtk_text_layout_create_display (GtkTextLayout *layout,
|
||||
size_only, FALSE);
|
||||
add_child_attrs (layout, display, style,
|
||||
seg, attrs, layout_byte_offset);
|
||||
memcpy (text + layout_byte_offset, _gtk_text_unknown_char_utf8,
|
||||
memcpy (text + layout_byte_offset, seg->body.child.obj->chars,
|
||||
seg->byte_count);
|
||||
layout_byte_offset += seg->byte_count;
|
||||
buffer_byte_offset += seg->byte_count;
|
||||
|
@ -1581,6 +1581,75 @@ test_get_iter (void)
|
||||
g_object_unref (buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
test_iter_with_anchor (void)
|
||||
{
|
||||
GtkTextView *text_view;
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter iter;
|
||||
GtkTextChildAnchor *anchor;
|
||||
GtkWidget *child;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (gtk_text_view_new ());
|
||||
buffer = gtk_text_view_get_buffer (text_view);
|
||||
|
||||
gtk_text_buffer_set_text (buffer, "ab\ncd\r\nef", -1);
|
||||
g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 1));
|
||||
anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
|
||||
child = gtk_label_new ("text");
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
g_object_unref (child);
|
||||
|
||||
gtk_text_buffer_get_iter_at_child_anchor (buffer, &iter, anchor);
|
||||
g_assert_cmpint (gtk_text_iter_get_char (&iter), ==, GTK_TEXT_UNKNOWN_CHAR);
|
||||
|
||||
g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 1));
|
||||
/* ß takes 2 bytes in UTF-8 */
|
||||
anchor = gtk_text_child_anchor_new_with_replacement ("ß");
|
||||
gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
|
||||
child = gtk_label_new ("text");
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
|
||||
gtk_text_buffer_get_iter_at_child_anchor (buffer, &iter, anchor);
|
||||
g_assert_cmpint (gtk_text_iter_get_char (&iter), ==, 223);
|
||||
|
||||
g_object_unref (child);
|
||||
g_object_ref_sink (text_view);
|
||||
}
|
||||
|
||||
static void
|
||||
test_get_text_with_anchor (void)
|
||||
{
|
||||
GtkTextView *text_view;
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter iter, start, end;
|
||||
GtkTextChildAnchor *anchor;
|
||||
GtkWidget *child;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (gtk_text_view_new ());
|
||||
buffer = gtk_text_view_get_buffer (text_view);
|
||||
|
||||
gtk_text_buffer_set_text (buffer, "ab\ncd\r\nef", -1);
|
||||
g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 1));
|
||||
anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
|
||||
child = gtk_label_new ("text");
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
g_object_unref (child);
|
||||
|
||||
g_assert_true (gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 1));
|
||||
/* ß takes 2 bytes in UTF-8 */
|
||||
anchor = gtk_text_child_anchor_new_with_replacement ("ß");
|
||||
gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
|
||||
child = gtk_label_new ("text");
|
||||
gtk_text_view_add_child_at_anchor (text_view, child, anchor);
|
||||
|
||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||
g_assert_cmpstr (gtk_text_buffer_get_text (buffer, &start, &end, FALSE), ==, "ab\ncßd\r\nef");
|
||||
|
||||
g_object_unref (child);
|
||||
g_object_ref_sink (text_view);
|
||||
}
|
||||
|
||||
/* Check that basic undo works */
|
||||
static void
|
||||
test_undo0 (void)
|
||||
@ -1768,6 +1837,8 @@ main (int argc, char** argv)
|
||||
g_test_add_func ("/TextBuffer/Tag", test_tag);
|
||||
g_test_add_func ("/TextBuffer/Clipboard", test_clipboard);
|
||||
g_test_add_func ("/TextBuffer/Get iter", test_get_iter);
|
||||
g_test_add_func ("/TextBuffer/Iter with anchor", test_iter_with_anchor);
|
||||
g_test_add_func ("/TextBuffer/Get text with anchor", test_get_text_with_anchor);
|
||||
g_test_add_func ("/TextBuffer/Undo 0", test_undo0);
|
||||
g_test_add_func ("/TextBuffer/Undo 1", test_undo1);
|
||||
g_test_add_func ("/TextBuffer/Undo 2", test_undo2);
|
||||
|
Loading…
Reference in New Issue
Block a user