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);
17 #define gray50_width 2
18 #define gray50_height 2
19 static char gray50_bits[] = {
24 create_tags (GtkTextBuffer *buffer)
28 /* Create a bunch of tags. Note that it's also possible to
29 * create tags with gtk_text_tag_new() then add them to the
30 * tag table for the buffer, gtk_text_buffer_create_tag() is
31 * just a convenience function. Also note that you don't have
32 * to give tags a name; pass NULL for the name to create an
35 * In any real app, another useful optimization would be to create
36 * a GtkTextTagTable in advance, and reuse the same tag table for
37 * all the buffers with the same tag set, instead of creating
38 * new copies of the same tags for every buffer.
40 * Tags are assigned default priorities in order of addition to the
41 * tag table. That is, tags created later that affect the same text
42 * property affected by an earlier tag will override the earlier
43 * tag. You can modify tag priorities with
44 * gtk_text_tag_set_priority().
47 gtk_text_buffer_create_tag (buffer, "heading",
48 "weight", PANGO_WEIGHT_BOLD,
49 "size", 15 * PANGO_SCALE,
52 gtk_text_buffer_create_tag (buffer, "italic",
53 "style", PANGO_STYLE_ITALIC, NULL);
55 gtk_text_buffer_create_tag (buffer, "bold",
56 "weight", PANGO_WEIGHT_BOLD, NULL);
58 gtk_text_buffer_create_tag (buffer, "big",
59 /* points times the PANGO_SCALE factor */
60 "size", 20 * PANGO_SCALE, NULL);
62 gtk_text_buffer_create_tag (buffer, "xx-small",
63 "scale", PANGO_SCALE_XX_SMALL, NULL);
65 gtk_text_buffer_create_tag (buffer, "x-large",
66 "scale", PANGO_SCALE_X_LARGE, NULL);
68 gtk_text_buffer_create_tag (buffer, "monospace",
69 "family", "monospace", NULL);
71 gtk_text_buffer_create_tag (buffer, "blue_foreground",
72 "foreground", "blue", NULL);
74 gtk_text_buffer_create_tag (buffer, "red_background",
75 "background", "red", NULL);
77 stipple = gdk_bitmap_create_from_data (NULL,
78 gray50_bits, gray50_width,
81 gtk_text_buffer_create_tag (buffer, "background_stipple",
82 "background_stipple", stipple, NULL);
84 gtk_text_buffer_create_tag (buffer, "foreground_stipple",
85 "foreground_stipple", stipple, NULL);
87 g_object_unref (stipple);
89 gtk_text_buffer_create_tag (buffer, "big_gap_before_line",
90 "pixels_above_lines", 30, NULL);
92 gtk_text_buffer_create_tag (buffer, "big_gap_after_line",
93 "pixels_below_lines", 30, NULL);
95 gtk_text_buffer_create_tag (buffer, "double_spaced_line",
96 "pixels_inside_wrap", 10, NULL);
98 gtk_text_buffer_create_tag (buffer, "not_editable",
99 "editable", FALSE, NULL);
101 gtk_text_buffer_create_tag (buffer, "word_wrap",
102 "wrap_mode", GTK_WRAP_WORD, NULL);
104 gtk_text_buffer_create_tag (buffer, "char_wrap",
105 "wrap_mode", GTK_WRAP_CHAR, NULL);
107 gtk_text_buffer_create_tag (buffer, "no_wrap",
108 "wrap_mode", GTK_WRAP_NONE, NULL);
110 gtk_text_buffer_create_tag (buffer, "center",
111 "justification", GTK_JUSTIFY_CENTER, NULL);
113 gtk_text_buffer_create_tag (buffer, "right_justify",
114 "justification", GTK_JUSTIFY_RIGHT, NULL);
116 gtk_text_buffer_create_tag (buffer, "wide_margins",
117 "left_margin", 50, "right_margin", 50,
120 gtk_text_buffer_create_tag (buffer, "strikethrough",
121 "strikethrough", TRUE, NULL);
123 gtk_text_buffer_create_tag (buffer, "underline",
124 "underline", PANGO_UNDERLINE_SINGLE, NULL);
126 gtk_text_buffer_create_tag (buffer, "double_underline",
127 "underline", PANGO_UNDERLINE_DOUBLE, NULL);
129 gtk_text_buffer_create_tag (buffer, "superscript",
130 "rise", 10 * PANGO_SCALE, /* 10 pixels */
131 "size", 8 * PANGO_SCALE, /* 8 points */
134 gtk_text_buffer_create_tag (buffer, "subscript",
135 "rise", -10 * PANGO_SCALE, /* 10 pixels */
136 "size", 8 * PANGO_SCALE, /* 8 points */
139 gtk_text_buffer_create_tag (buffer, "rtl_quote",
140 "wrap_mode", GTK_WRAP_WORD,
141 "direction", GTK_TEXT_DIR_RTL,
149 insert_text (GtkTextBuffer *buffer)
152 GtkTextIter start, end;
155 GtkTextChildAnchor *anchor;
158 /* demo_find_file() looks in the current directory first,
159 * so you can run gtk-demo without installing GTK, then looks
160 * in the location where the file is installed.
163 filename = demo_find_file ("gtk-logo-rgb.gif", NULL);
166 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
172 g_printerr ("Failed to load image file gtk-logo-rgb.gif\n");
176 scaled = gdk_pixbuf_scale_simple (pixbuf, 32, 32, GDK_INTERP_BILINEAR);
177 g_object_unref (pixbuf);
180 /* get start of buffer; each insertion will revalidate the
181 * iterator to point to just after the inserted text.
183 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
185 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);
187 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Font styles. ", -1,
190 gtk_text_buffer_insert (buffer, &iter, "For example, you can have ", -1);
191 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
194 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
195 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
198 gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
199 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
200 "monospace (typewriter)", -1,
202 gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
203 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
206 gtk_text_buffer_insert (buffer, &iter, " text. ", -1);
207 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);
208 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
211 gtk_text_buffer_insert (buffer, &iter, " or ", -1);
212 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
215 gtk_text_buffer_insert (buffer, &iter, " to ensure that your program properly adapts if the user changes the default font size.\n\n", -1);
217 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Colors. ", -1,
220 gtk_text_buffer_insert (buffer, &iter, "Colors such as ", -1);
221 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
222 "a blue foreground", -1,
223 "blue_foreground", NULL);
224 gtk_text_buffer_insert (buffer, &iter, " or ", -1);
225 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
226 "a red background", -1,
227 "red_background", NULL);
228 gtk_text_buffer_insert (buffer, &iter, " or even ", -1);
229 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
230 "a stippled red background", -1,
232 "background_stipple",
235 gtk_text_buffer_insert (buffer, &iter, " or ", -1);
236 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
237 "a stippled blue foreground on solid red background", -1,
240 "foreground_stipple",
242 gtk_text_buffer_insert (buffer, &iter, " (select that to read it) can be used.\n\n", -1);
244 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Underline, strikethrough, and rise. ", -1,
247 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
249 "strikethrough", NULL);
250 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
251 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
254 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
255 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
256 "double underline", -1,
257 "double_underline", NULL);
258 gtk_text_buffer_insert (buffer, &iter, ", ", -1);
259 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
261 "superscript", NULL);
262 gtk_text_buffer_insert (buffer, &iter, ", and ", -1);
263 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
266 gtk_text_buffer_insert (buffer, &iter, " are all supported.\n\n", -1);
268 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Images. ", -1,
271 gtk_text_buffer_insert (buffer, &iter, "The buffer can have images in it: ", -1);
272 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
273 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
274 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
275 gtk_text_buffer_insert (buffer, &iter, " for example.\n\n", -1);
277 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Spacing. ", -1,
280 gtk_text_buffer_insert (buffer, &iter, "You can adjust the amount of space before each line.\n", -1);
282 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
283 "This line has a whole lot of space before it.\n", -1,
284 "big_gap_before_line", "wide_margins", NULL);
285 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
286 "You can also adjust the amount of space after each line; this line has a whole lot of space after it.\n", -1,
287 "big_gap_after_line", "wide_margins", NULL);
289 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
290 "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,
291 "double_spaced_line", "wide_margins", NULL);
293 gtk_text_buffer_insert (buffer, &iter, "Also note that those lines have extra-wide margins.\n\n", -1);
295 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Editability. ", -1,
298 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
299 "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,
300 "not_editable", NULL);
302 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Wrapping. ", -1,
305 gtk_text_buffer_insert (buffer, &iter,
306 "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);
308 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
309 "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,
312 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
313 "This line has all wrapping turned off, so it makes the horizontal scrollbar appear.\n\n\n", -1,
316 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Justification. ", -1,
319 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
320 "\nThis line has center justification.\n", -1,
323 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
324 "This line has right justification.\n", -1,
325 "right_justify", NULL);
327 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
328 "\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,
329 "wide_margins", NULL);
331 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Internationalization. ", -1,
334 gtk_text_buffer_insert (buffer, &iter,
335 "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);
337 gtk_text_buffer_insert (buffer, &iter, "Here's a word-wrapped quote in a right-to-left language:\n", -1);
338 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,
341 gtk_text_buffer_insert (buffer, &iter, "You can put widgets in the buffer: Here's a button: ", -1);
342 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
343 gtk_text_buffer_insert (buffer, &iter, " and a menu: ", -1);
344 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
345 gtk_text_buffer_insert (buffer, &iter, " and a scale: ", -1);
346 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
347 gtk_text_buffer_insert (buffer, &iter, " and an animation: ", -1);
348 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
349 gtk_text_buffer_insert (buffer, &iter, " finally a text entry: ", -1);
350 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
351 gtk_text_buffer_insert (buffer, &iter, ".\n", -1);
353 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);
355 /* Apply word_wrap tag to whole buffer */
356 gtk_text_buffer_get_bounds (buffer, &start, &end);
357 gtk_text_buffer_apply_tag_by_name (buffer, "word_wrap", &start, &end);
359 g_object_unref (pixbuf);
363 find_anchor (GtkTextIter *iter)
365 while (gtk_text_iter_forward_char (iter))
367 if (gtk_text_iter_get_child_anchor (iter))
374 attach_widgets (GtkTextView *text_view)
377 GtkTextBuffer *buffer;
380 buffer = gtk_text_view_get_buffer (text_view);
382 gtk_text_buffer_get_start_iter (buffer, &iter);
385 while (find_anchor (&iter))
387 GtkTextChildAnchor *anchor;
390 anchor = gtk_text_iter_get_child_anchor (&iter);
394 widget = gtk_button_new_with_label ("Click Me");
396 g_signal_connect (widget, "clicked",
397 G_CALLBACK (easter_egg_callback),
402 widget = gtk_combo_box_new_text ();
404 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Option 1");
405 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Option 2");
406 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Option 3");
410 widget = gtk_hscale_new (NULL);
411 gtk_range_set_range (GTK_RANGE (widget), 0, 100);
412 gtk_widget_set_size_request (widget, 70, -1);
416 gchar *filename = demo_find_file ("floppybuddy.gif", NULL);
417 widget = gtk_image_new_from_file (filename);
422 widget = gtk_entry_new ();
426 widget = NULL; /* avoids a compiler warning */
427 g_assert_not_reached ();
430 gtk_text_view_add_child_at_anchor (text_view,
434 gtk_widget_show_all (widget);
441 do_textview (GtkWidget *do_widget)
443 static GtkWidget *window = NULL;
451 GtkTextBuffer *buffer;
453 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
454 gtk_window_set_screen (GTK_WINDOW (window),
455 gtk_widget_get_screen (do_widget));
456 gtk_window_set_default_size (GTK_WINDOW (window),
459 g_signal_connect (window, "destroy",
460 G_CALLBACK (gtk_widget_destroyed), &window);
462 gtk_window_set_title (GTK_WINDOW (window), "TextView");
463 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
465 vpaned = gtk_vpaned_new ();
466 gtk_container_set_border_width (GTK_CONTAINER(vpaned), 5);
467 gtk_container_add (GTK_CONTAINER (window), vpaned);
469 /* For convenience, we just use the autocreated buffer from
470 * the first text view; you could also create the buffer
471 * by itself with gtk_text_buffer_new(), then later create
474 view1 = gtk_text_view_new ();
475 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view1));
476 view2 = gtk_text_view_new_with_buffer (buffer);
478 sw = gtk_scrolled_window_new (NULL, NULL);
479 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
480 GTK_POLICY_AUTOMATIC,
481 GTK_POLICY_AUTOMATIC);
482 gtk_paned_add1 (GTK_PANED (vpaned), sw);
484 gtk_container_add (GTK_CONTAINER (sw), view1);
486 sw = gtk_scrolled_window_new (NULL, NULL);
487 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
488 GTK_POLICY_AUTOMATIC,
489 GTK_POLICY_AUTOMATIC);
490 gtk_paned_add2 (GTK_PANED (vpaned), sw);
492 gtk_container_add (GTK_CONTAINER (sw), view2);
494 create_tags (buffer);
495 insert_text (buffer);
497 attach_widgets (GTK_TEXT_VIEW (view1));
498 attach_widgets (GTK_TEXT_VIEW (view2));
500 gtk_widget_show_all (vpaned);
503 if (!gtk_widget_get_visible (window))
505 gtk_widget_show (window);
509 gtk_widget_destroy (window);
517 recursive_attach_view (int depth,
519 GtkTextChildAnchor *anchor)
521 GtkWidget *child_view;
522 GtkWidget *event_box;
529 child_view = gtk_text_view_new_with_buffer (gtk_text_view_get_buffer (view));
531 /* Event box is to add a black border around each child view */
532 event_box = gtk_event_box_new ();
533 gdk_color_parse ("black", &color);
534 gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
536 align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
537 gtk_container_set_border_width (GTK_CONTAINER (align), 1);
539 gtk_container_add (GTK_CONTAINER (event_box), align);
540 gtk_container_add (GTK_CONTAINER (align), child_view);
542 gtk_text_view_add_child_at_anchor (view, event_box, anchor);
544 recursive_attach_view (depth + 1, GTK_TEXT_VIEW (child_view), anchor);
548 easter_egg_callback (GtkWidget *button,
551 static GtkWidget *window = NULL;
553 GtkTextBuffer *buffer;
556 GtkTextChildAnchor *anchor;
561 gtk_window_present (GTK_WINDOW (window));
565 buffer = gtk_text_buffer_new (NULL);
567 gtk_text_buffer_get_start_iter (buffer, &iter);
569 gtk_text_buffer_insert (buffer, &iter,
570 "This buffer is shared by a set of nested text views.\n Nested view:\n", -1);
571 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
572 gtk_text_buffer_insert (buffer, &iter,
573 "\nDon't do this in real applications, please.\n", -1);
575 view = gtk_text_view_new_with_buffer (buffer);
577 recursive_attach_view (0, GTK_TEXT_VIEW (view), anchor);
579 g_object_unref (buffer);
581 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
582 sw = gtk_scrolled_window_new (NULL, NULL);
583 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
584 GTK_POLICY_AUTOMATIC,
585 GTK_POLICY_AUTOMATIC);
587 gtk_container_add (GTK_CONTAINER (window), sw);
588 gtk_container_add (GTK_CONTAINER (sw), view);
590 window_ptr = &window;
591 g_object_add_weak_pointer (G_OBJECT (window), window_ptr);
593 gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
595 gtk_widget_show_all (window);