1 /* Text Widget/Multiple Views
3 * The GtkTextView widget displays a GtkTextBuffer. One GtkTextBuffer
4 * can be displayed by multiple GtkTextViews. This demo has two views
5 * displaying a single buffer, and shows off the widget's text
11 #include <stdlib.h> /* for exit() */
13 #include "demo-common.h"
15 static void easter_egg_callback (GtkWidget *button, gpointer data);
18 create_tags (GtkTextBuffer *buffer)
20 /* Create a bunch of tags. Note that it's also possible to
21 * create tags with gtk_text_tag_new() then add them to the
22 * tag table for the buffer, gtk_text_buffer_create_tag() is
23 * just a convenience function. Also note that you don't have
24 * to give tags a name; pass NULL for the name to create an
27 * In any real app, another useful optimization would be to create
28 * a GtkTextTagTable in advance, and reuse the same tag table for
29 * all the buffers with the same tag set, instead of creating
30 * new copies of the same tags for every buffer.
32 * Tags are assigned default priorities in order of addition to the
33 * tag table. That is, tags created later that affect the same text
34 * property affected by an earlier tag will override the earlier
35 * tag. You can modify tag priorities with
36 * gtk_text_tag_set_priority().
39 gtk_text_buffer_create_tag (buffer, "heading",
40 "weight", PANGO_WEIGHT_BOLD,
41 "size", 15 * PANGO_SCALE,
44 gtk_text_buffer_create_tag (buffer, "italic",
45 "style", PANGO_STYLE_ITALIC, NULL);
47 gtk_text_buffer_create_tag (buffer, "bold",
48 "weight", PANGO_WEIGHT_BOLD, NULL);
50 gtk_text_buffer_create_tag (buffer, "big",
51 /* points times the PANGO_SCALE factor */
52 "size", 20 * PANGO_SCALE, NULL);
54 gtk_text_buffer_create_tag (buffer, "xx-small",
55 "scale", PANGO_SCALE_XX_SMALL, NULL);
57 gtk_text_buffer_create_tag (buffer, "x-large",
58 "scale", PANGO_SCALE_X_LARGE, NULL);
60 gtk_text_buffer_create_tag (buffer, "monospace",
61 "family", "monospace", NULL);
63 gtk_text_buffer_create_tag (buffer, "blue_foreground",
64 "foreground", "blue", NULL);
66 gtk_text_buffer_create_tag (buffer, "red_background",
67 "background", "red", NULL);
69 gtk_text_buffer_create_tag (buffer, "big_gap_before_line",
70 "pixels_above_lines", 30, NULL);
72 gtk_text_buffer_create_tag (buffer, "big_gap_after_line",
73 "pixels_below_lines", 30, NULL);
75 gtk_text_buffer_create_tag (buffer, "double_spaced_line",
76 "pixels_inside_wrap", 10, NULL);
78 gtk_text_buffer_create_tag (buffer, "not_editable",
79 "editable", FALSE, NULL);
81 gtk_text_buffer_create_tag (buffer, "word_wrap",
82 "wrap_mode", GTK_WRAP_WORD, NULL);
84 gtk_text_buffer_create_tag (buffer, "char_wrap",
85 "wrap_mode", GTK_WRAP_CHAR, NULL);
87 gtk_text_buffer_create_tag (buffer, "no_wrap",
88 "wrap_mode", GTK_WRAP_NONE, NULL);
90 gtk_text_buffer_create_tag (buffer, "center",
91 "justification", GTK_JUSTIFY_CENTER, NULL);
93 gtk_text_buffer_create_tag (buffer, "right_justify",
94 "justification", GTK_JUSTIFY_RIGHT, NULL);
96 gtk_text_buffer_create_tag (buffer, "wide_margins",
97 "left_margin", 50, "right_margin", 50,
100 gtk_text_buffer_create_tag (buffer, "strikethrough",
101 "strikethrough", TRUE, NULL);
103 gtk_text_buffer_create_tag (buffer, "underline",
104 "underline", PANGO_UNDERLINE_SINGLE, NULL);
106 gtk_text_buffer_create_tag (buffer, "double_underline",
107 "underline", PANGO_UNDERLINE_DOUBLE, NULL);
109 gtk_text_buffer_create_tag (buffer, "superscript",
110 "rise", 10 * PANGO_SCALE, /* 10 pixels */
111 "size", 8 * PANGO_SCALE, /* 8 points */
114 gtk_text_buffer_create_tag (buffer, "subscript",
115 "rise", -10 * PANGO_SCALE, /* 10 pixels */
116 "size", 8 * PANGO_SCALE, /* 8 points */
119 gtk_text_buffer_create_tag (buffer, "rtl_quote",
120 "wrap_mode", GTK_WRAP_WORD,
121 "direction", GTK_TEXT_DIR_RTL,
129 insert_text (GtkTextBuffer *buffer)
132 GtkTextIter start, end;
135 GtkTextChildAnchor *anchor;
138 /* demo_find_file() looks in the current directory first,
139 * so you can run gtk-demo without installing GTK, then looks
140 * in the location where the file is installed.
143 filename = demo_find_file ("gtk-logo-rgb.gif", NULL);
146 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
152 g_printerr ("Failed to load image file gtk-logo-rgb.gif\n");
156 scaled = gdk_pixbuf_scale_simple (pixbuf, 32, 32, GDK_INTERP_BILINEAR);
157 g_object_unref (pixbuf);
160 /* get start of buffer; each insertion will revalidate the
161 * iterator to point to just after the inserted text.
163 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
165 gtk_text_buffer_insert (buffer, &iter, "The text widget can display text with all kinds of nifty attributes. It also supports multiple views of the same buffer; this demo is showing the same buffer in two places.\n\n", -1);
167 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Font styles. ", -1,
170 gtk_text_buffer_insert (buffer, &iter, "For example, you can have ", -1);
171 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
174 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
175 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
178 gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
179 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
180 "monospace (typewriter)", -1,
182 gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
183 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
186 gtk_text_buffer_insert (buffer, &iter, " text. ", -1);
187 gtk_text_buffer_insert (buffer, &iter, "It's best not to hardcode specific text sizes; you can use relative sizes as with CSS, such as ", -1);
188 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
191 gtk_text_buffer_insert (buffer, &iter, " or ", -1);
192 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
195 gtk_text_buffer_insert (buffer, &iter, " to ensure that your program properly adapts if the user changes the default font size.\n\n", -1);
197 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Colors. ", -1,
200 gtk_text_buffer_insert (buffer, &iter, "Colors such as ", -1);
201 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
202 "a blue foreground", -1,
203 "blue_foreground", NULL);
204 gtk_text_buffer_insert (buffer, &iter, " or ", -1);
205 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
206 "a red background", -1,
207 "red_background", NULL);
208 gtk_text_buffer_insert (buffer, &iter, " or even ", -1);
209 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
210 "a blue foreground on red background", -1,
214 gtk_text_buffer_insert (buffer, &iter, " (select that to read it) can be used.\n\n", -1);
216 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Underline, strikethrough, and rise. ", -1,
219 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
221 "strikethrough", NULL);
222 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
223 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
226 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
227 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
228 "double underline", -1,
229 "double_underline", NULL);
230 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
231 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
233 "superscript", NULL);
234 gtk_text_buffer_insert (buffer, &iter, ", and ", -1);
235 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
238 gtk_text_buffer_insert (buffer, &iter, " are all supported.\n\n", -1);
240 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Images. ", -1,
243 gtk_text_buffer_insert (buffer, &iter, "The buffer can have images in it: ", -1);
244 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
245 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
246 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
247 gtk_text_buffer_insert (buffer, &iter, " for example.\n\n", -1);
249 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Spacing. ", -1,
252 gtk_text_buffer_insert (buffer, &iter, "You can adjust the amount of space before each line.\n", -1);
254 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
255 "This line has a whole lot of space before it.\n", -1,
256 "big_gap_before_line", "wide_margins", NULL);
257 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
258 "You can also adjust the amount of space after each line; this line has a whole lot of space after it.\n", -1,
259 "big_gap_after_line", "wide_margins", NULL);
261 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
262 "You can also adjust the amount of space between wrapped lines; this line has extra space between each wrapped line in the same paragraph. To show off wrapping, some filler text: the quick brown fox jumped over the lazy dog. Blah blah blah blah blah blah blah blah blah.\n", -1,
263 "double_spaced_line", "wide_margins", NULL);
265 gtk_text_buffer_insert (buffer, &iter, "Also note that those lines have extra-wide margins.\n\n", -1);
267 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Editability. ", -1,
270 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
271 "This line is 'locked down' and can't be edited by the user - just try it! You can't delete this line.\n\n", -1,
272 "not_editable", NULL);
274 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Wrapping. ", -1,
277 gtk_text_buffer_insert (buffer, &iter,
278 "This line (and most of the others in this buffer) is word-wrapped, using the proper Unicode algorithm. Word wrap should work in all scripts and languages that GTK+ supports. Let's make this a long paragraph to demonstrate: blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah\n\n", -1);
280 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
281 "This line has character-based wrapping, and can wrap between any two character glyphs. Let's make this a long paragraph to demonstrate: blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah\n\n", -1,
284 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
285 "This line has all wrapping turned off, so it makes the horizontal scrollbar appear.\n\n\n", -1,
288 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Justification. ", -1,
291 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
292 "\nThis line has center justification.\n", -1,
295 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
296 "This line has right justification.\n", -1,
297 "right_justify", NULL);
299 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
300 "\nThis line has big wide margins. Text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text.\n", -1,
301 "wide_margins", NULL);
303 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Internationalization. ", -1,
306 gtk_text_buffer_insert (buffer, &iter,
307 "You can put all sorts of Unicode text in the buffer.\n\nGerman (Deutsch S\303\274d) Gr\303\274\303\237 Gott\nGreek (\316\225\316\273\316\273\316\267\316\275\316\271\316\272\316\254) \316\223\316\265\316\271\316\254 \317\203\316\261\317\202\nHebrew \327\251\327\234\327\225\327\235\nJapanese (\346\227\245\346\234\254\350\252\236)\n\nThe widget properly handles bidirectional text, word wrapping, DOS/UNIX/Unicode paragraph separators, grapheme boundaries, and so on using the Pango internationalization framework.\n", -1);
309 gtk_text_buffer_insert (buffer, &iter, "Here's a word-wrapped quote in a right-to-left language:\n", -1);
310 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "\331\210\331\202\330\257 \330\250\330\257\330\243 \330\253\331\204\330\247\330\253 \331\205\331\206 \330\243\331\203\330\253\330\261 \330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 \330\252\331\202\330\257\331\205\330\247 \331\201\331\212 \330\264\330\250\331\203\330\251 \330\247\331\203\330\263\331\212\331\210\331\206 \330\250\330\261\330\247\331\205\330\254\331\207\330\247 \331\203\331\205\331\206\330\270\331\205\330\247\330\252 \331\204\330\247 \330\252\330\263\330\271\331\211 \331\204\331\204\330\261\330\250\330\255\330\214 \330\253\331\205 \330\252\330\255\331\210\331\204\330\252 \331\201\331\212 \330\247\331\204\330\263\331\206\331\210\330\247\330\252 \330\247\331\204\330\256\331\205\330\263 \330\247\331\204\331\205\330\247\330\266\331\212\330\251 \330\245\331\204\331\211 \331\205\330\244\330\263\330\263\330\247\330\252 \331\205\330\247\331\204\331\212\330\251 \331\205\331\206\330\270\331\205\330\251\330\214 \331\210\330\250\330\247\330\252\330\252 \330\254\330\262\330\241\330\247 \331\205\331\206 \330\247\331\204\331\206\330\270\330\247\331\205 \330\247\331\204\331\205\330\247\331\204\331\212 \331\201\331\212 \330\250\331\204\330\257\330\247\331\206\331\207\330\247\330\214 \331\210\331\204\331\203\331\206\331\207\330\247 \330\252\330\252\330\256\330\265\330\265 \331\201\331\212 \330\256\330\257\331\205\330\251 \331\202\330\267\330\247\330\271 \330\247\331\204\331\205\330\264\330\261\331\210\330\271\330\247\330\252 \330\247\331\204\330\265\330\272\331\212\330\261\330\251. \331\210\330\243\330\255\330\257 \330\243\331\203\330\253\330\261 \331\207\330\260\331\207 \330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 \331\206\330\254\330\247\330\255\330\247 \331\207\331\210 \302\273\330\250\330\247\331\206\331\203\331\210\330\263\331\210\331\204\302\253 \331\201\331\212 \330\250\331\210\331\204\331\212\331\201\331\212\330\247.\n\n", -1,
313 gtk_text_buffer_insert (buffer, &iter, "You can put widgets in the buffer: Here's a button: ", -1);
314 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
315 gtk_text_buffer_insert (buffer, &iter, " and a menu: ", -1);
316 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
317 gtk_text_buffer_insert (buffer, &iter, " and a scale: ", -1);
318 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
319 gtk_text_buffer_insert (buffer, &iter, " and an animation: ", -1);
320 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
321 gtk_text_buffer_insert (buffer, &iter, " finally a text entry: ", -1);
322 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
323 gtk_text_buffer_insert (buffer, &iter, ".\n", -1);
325 gtk_text_buffer_insert (buffer, &iter, "\n\nThis demo doesn't demonstrate all the GtkTextBuffer features; it leaves out, for example: invisible/hidden text, tab stops, application-drawn areas on the sides of the widget for displaying breakpoints and such...", -1);
327 /* Apply word_wrap tag to whole buffer */
328 gtk_text_buffer_get_bounds (buffer, &start, &end);
329 gtk_text_buffer_apply_tag_by_name (buffer, "word_wrap", &start, &end);
331 g_object_unref (pixbuf);
335 find_anchor (GtkTextIter *iter)
337 while (gtk_text_iter_forward_char (iter))
339 if (gtk_text_iter_get_child_anchor (iter))
346 attach_widgets (GtkTextView *text_view)
349 GtkTextBuffer *buffer;
352 buffer = gtk_text_view_get_buffer (text_view);
354 gtk_text_buffer_get_start_iter (buffer, &iter);
357 while (find_anchor (&iter))
359 GtkTextChildAnchor *anchor;
362 anchor = gtk_text_iter_get_child_anchor (&iter);
366 widget = gtk_button_new_with_label ("Click Me");
368 g_signal_connect (widget, "clicked",
369 G_CALLBACK (easter_egg_callback),
374 widget = gtk_combo_box_text_new ();
376 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Option 1");
377 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Option 2");
378 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Option 3");
382 widget = gtk_hscale_new (NULL);
383 gtk_range_set_range (GTK_RANGE (widget), 0, 100);
384 gtk_widget_set_size_request (widget, 70, -1);
388 gchar *filename = demo_find_file ("floppybuddy.gif", NULL);
389 widget = gtk_image_new_from_file (filename);
394 widget = gtk_entry_new ();
398 widget = NULL; /* avoids a compiler warning */
399 g_assert_not_reached ();
402 gtk_text_view_add_child_at_anchor (text_view,
406 gtk_widget_show_all (widget);
413 do_textview (GtkWidget *do_widget)
415 static GtkWidget *window = NULL;
423 GtkTextBuffer *buffer;
425 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
426 gtk_window_set_screen (GTK_WINDOW (window),
427 gtk_widget_get_screen (do_widget));
428 gtk_window_set_default_size (GTK_WINDOW (window),
431 g_signal_connect (window, "destroy",
432 G_CALLBACK (gtk_widget_destroyed), &window);
434 gtk_window_set_title (GTK_WINDOW (window), "TextView");
435 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
437 vpaned = gtk_vpaned_new ();
438 gtk_container_set_border_width (GTK_CONTAINER(vpaned), 5);
439 gtk_container_add (GTK_CONTAINER (window), vpaned);
441 /* For convenience, we just use the autocreated buffer from
442 * the first text view; you could also create the buffer
443 * by itself with gtk_text_buffer_new(), then later create
446 view1 = gtk_text_view_new ();
447 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view1));
448 view2 = gtk_text_view_new_with_buffer (buffer);
450 sw = gtk_scrolled_window_new (NULL, NULL);
451 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
452 GTK_POLICY_AUTOMATIC,
453 GTK_POLICY_AUTOMATIC);
454 gtk_paned_add1 (GTK_PANED (vpaned), sw);
456 gtk_container_add (GTK_CONTAINER (sw), view1);
458 sw = gtk_scrolled_window_new (NULL, NULL);
459 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
460 GTK_POLICY_AUTOMATIC,
461 GTK_POLICY_AUTOMATIC);
462 gtk_paned_add2 (GTK_PANED (vpaned), sw);
464 gtk_container_add (GTK_CONTAINER (sw), view2);
466 create_tags (buffer);
467 insert_text (buffer);
469 attach_widgets (GTK_TEXT_VIEW (view1));
470 attach_widgets (GTK_TEXT_VIEW (view2));
472 gtk_widget_show_all (vpaned);
475 if (!gtk_widget_get_visible (window))
477 gtk_widget_show (window);
481 gtk_widget_destroy (window);
489 recursive_attach_view (int depth,
491 GtkTextChildAnchor *anchor)
493 GtkWidget *child_view;
494 GtkWidget *event_box;
501 child_view = gtk_text_view_new_with_buffer (gtk_text_view_get_buffer (view));
503 /* Event box is to add a black border around each child view */
504 event_box = gtk_event_box_new ();
505 gdk_color_parse ("black", &color);
506 gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
508 align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
509 gtk_container_set_border_width (GTK_CONTAINER (align), 1);
511 gtk_container_add (GTK_CONTAINER (event_box), align);
512 gtk_container_add (GTK_CONTAINER (align), child_view);
514 gtk_text_view_add_child_at_anchor (view, event_box, anchor);
516 recursive_attach_view (depth + 1, GTK_TEXT_VIEW (child_view), anchor);
520 easter_egg_callback (GtkWidget *button,
523 static GtkWidget *window = NULL;
525 GtkTextBuffer *buffer;
528 GtkTextChildAnchor *anchor;
533 gtk_window_present (GTK_WINDOW (window));
537 buffer = gtk_text_buffer_new (NULL);
539 gtk_text_buffer_get_start_iter (buffer, &iter);
541 gtk_text_buffer_insert (buffer, &iter,
542 "This buffer is shared by a set of nested text views.\n Nested view:\n", -1);
543 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
544 gtk_text_buffer_insert (buffer, &iter,
545 "\nDon't do this in real applications, please.\n", -1);
547 view = gtk_text_view_new_with_buffer (buffer);
549 recursive_attach_view (0, GTK_TEXT_VIEW (view), anchor);
551 g_object_unref (buffer);
553 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
554 sw = gtk_scrolled_window_new (NULL, NULL);
555 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
556 GTK_POLICY_AUTOMATIC,
557 GTK_POLICY_AUTOMATIC);
559 gtk_container_add (GTK_CONTAINER (window), sw);
560 gtk_container_add (GTK_CONTAINER (sw), view);
562 window_ptr = &window;
563 g_object_add_weak_pointer (G_OBJECT (window), window_ptr);
565 gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
567 gtk_widget_show_all (window);