1 | /* Text View/Multiple Views |
2 | * |
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 |
6 | * formatting features. |
7 | * |
8 | */ |
9 | |
10 | #include <gtk/gtk.h> |
11 | #include <stdlib.h> /* for exit() */ |
12 | #include "paintable.h" |
13 | |
14 | static void easter_egg_callback (GtkWidget *button, gpointer data); |
15 | |
16 | static void |
17 | create_tags (GtkTextBuffer *buffer) |
18 | { |
19 | /* Create a bunch of tags. Note that it's also possible to |
20 | * create tags with gtk_text_tag_new() then add them to the |
21 | * tag table for the buffer, gtk_text_buffer_create_tag() is |
22 | * just a convenience function. Also note that you don't have |
23 | * to give tags a name; pass NULL for the name to create an |
24 | * anonymous tag. |
25 | * |
26 | * In any real app, another useful optimization would be to create |
27 | * a GtkTextTagTable in advance, and reuse the same tag table for |
28 | * all the buffers with the same tag set, instead of creating |
29 | * new copies of the same tags for every buffer. |
30 | * |
31 | * Tags are assigned default priorities in order of addition to the |
32 | * tag table. That is, tags created later that affect the same text |
33 | * property affected by an earlier tag will override the earlier |
34 | * tag. You can modify tag priorities with |
35 | * gtk_text_tag_set_priority(). |
36 | */ |
37 | |
38 | gtk_text_buffer_create_tag (buffer, tag_name: "heading" , |
39 | first_property_name: "weight" , PANGO_WEIGHT_BOLD, |
40 | "size" , 15 * PANGO_SCALE, |
41 | NULL); |
42 | |
43 | gtk_text_buffer_create_tag (buffer, tag_name: "italic" , |
44 | first_property_name: "style" , PANGO_STYLE_ITALIC, NULL); |
45 | |
46 | gtk_text_buffer_create_tag (buffer, tag_name: "bold" , |
47 | first_property_name: "weight" , PANGO_WEIGHT_BOLD, NULL); |
48 | |
49 | gtk_text_buffer_create_tag (buffer, tag_name: "big" , |
50 | /* points times the PANGO_SCALE factor */ |
51 | first_property_name: "size" , 20 * PANGO_SCALE, NULL); |
52 | |
53 | gtk_text_buffer_create_tag (buffer, tag_name: "xx-small" , |
54 | first_property_name: "scale" , PANGO_SCALE_XX_SMALL, NULL); |
55 | |
56 | gtk_text_buffer_create_tag (buffer, tag_name: "x-large" , |
57 | first_property_name: "scale" , PANGO_SCALE_X_LARGE, NULL); |
58 | |
59 | gtk_text_buffer_create_tag (buffer, tag_name: "monospace" , |
60 | first_property_name: "family" , "monospace" , NULL); |
61 | |
62 | gtk_text_buffer_create_tag (buffer, tag_name: "blue_foreground" , |
63 | first_property_name: "foreground" , "blue" , NULL); |
64 | |
65 | gtk_text_buffer_create_tag (buffer, tag_name: "red_background" , |
66 | first_property_name: "background" , "red" , NULL); |
67 | |
68 | gtk_text_buffer_create_tag (buffer, tag_name: "big_gap_before_line" , |
69 | first_property_name: "pixels_above_lines" , 30, NULL); |
70 | |
71 | gtk_text_buffer_create_tag (buffer, tag_name: "big_gap_after_line" , |
72 | first_property_name: "pixels_below_lines" , 30, NULL); |
73 | |
74 | gtk_text_buffer_create_tag (buffer, tag_name: "double_spaced_line" , |
75 | first_property_name: "pixels_inside_wrap" , 10, NULL); |
76 | |
77 | gtk_text_buffer_create_tag (buffer, tag_name: "not_editable" , |
78 | first_property_name: "editable" , FALSE, NULL); |
79 | |
80 | gtk_text_buffer_create_tag (buffer, tag_name: "word_wrap" , |
81 | first_property_name: "wrap_mode" , GTK_WRAP_WORD, NULL); |
82 | |
83 | gtk_text_buffer_create_tag (buffer, tag_name: "char_wrap" , |
84 | first_property_name: "wrap_mode" , GTK_WRAP_CHAR, NULL); |
85 | |
86 | gtk_text_buffer_create_tag (buffer, tag_name: "no_wrap" , |
87 | first_property_name: "wrap_mode" , GTK_WRAP_NONE, NULL); |
88 | |
89 | gtk_text_buffer_create_tag (buffer, tag_name: "center" , |
90 | first_property_name: "justification" , GTK_JUSTIFY_CENTER, NULL); |
91 | |
92 | gtk_text_buffer_create_tag (buffer, tag_name: "right_justify" , |
93 | first_property_name: "justification" , GTK_JUSTIFY_RIGHT, NULL); |
94 | |
95 | gtk_text_buffer_create_tag (buffer, tag_name: "wide_margins" , |
96 | first_property_name: "left_margin" , 50, "right_margin" , 50, |
97 | NULL); |
98 | |
99 | gtk_text_buffer_create_tag (buffer, tag_name: "strikethrough" , |
100 | first_property_name: "strikethrough" , TRUE, NULL); |
101 | |
102 | gtk_text_buffer_create_tag (buffer, tag_name: "underline" , |
103 | first_property_name: "underline" , PANGO_UNDERLINE_SINGLE, NULL); |
104 | |
105 | gtk_text_buffer_create_tag (buffer, tag_name: "double_underline" , |
106 | first_property_name: "underline" , PANGO_UNDERLINE_DOUBLE, NULL); |
107 | |
108 | gtk_text_buffer_create_tag (buffer, tag_name: "superscript" , |
109 | first_property_name: "rise" , 10 * PANGO_SCALE, /* 10 pixels */ |
110 | "size" , 8 * PANGO_SCALE, /* 8 points */ |
111 | NULL); |
112 | |
113 | gtk_text_buffer_create_tag (buffer, tag_name: "subscript" , |
114 | first_property_name: "rise" , -10 * PANGO_SCALE, /* 10 pixels */ |
115 | "size" , 8 * PANGO_SCALE, /* 8 points */ |
116 | NULL); |
117 | |
118 | gtk_text_buffer_create_tag (buffer, tag_name: "rtl_quote" , |
119 | first_property_name: "wrap_mode" , GTK_WRAP_WORD, |
120 | "direction" , GTK_TEXT_DIR_RTL, |
121 | "indent" , 30, |
122 | "left_margin" , 20, |
123 | "right_margin" , 20, |
124 | NULL); |
125 | } |
126 | |
127 | static void |
128 | insert_text (GtkTextView *view) |
129 | { |
130 | GtkWidget *widget = GTK_WIDGET (view); |
131 | GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view: view); |
132 | GtkTextIter iter; |
133 | GtkTextIter start, end; |
134 | GtkIconTheme *icon_theme; |
135 | GtkIconPaintable *icon; |
136 | GdkPaintable *nuclear; |
137 | |
138 | icon_theme = gtk_icon_theme_get_for_display (display: gtk_widget_get_display (widget)); |
139 | icon = gtk_icon_theme_lookup_icon (self: icon_theme, |
140 | icon_name: "face-cool" , |
141 | NULL, |
142 | size: 32, scale: 1, |
143 | direction: gtk_widget_get_direction (widget), |
144 | flags: 0); |
145 | nuclear = gtk_nuclear_animation_new (TRUE); |
146 | |
147 | /* get start of buffer; each insertion will revalidate the |
148 | * iterator to point to just after the inserted text. |
149 | */ |
150 | gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: 0); |
151 | |
152 | gtk_text_buffer_begin_irreversible_action (buffer); |
153 | gtk_text_buffer_insert (buffer, iter: &iter, |
154 | text: "The text widget can display text with all kinds of nifty attributes. " |
155 | "It also supports multiple views of the same buffer; this demo is " |
156 | "showing the same buffer in two places.\n\n" , len: -1); |
157 | |
158 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
159 | text: "Font styles. " , len: -1, |
160 | first_tag_name: "heading" , NULL); |
161 | |
162 | gtk_text_buffer_insert (buffer, iter: &iter, text: "For example, you can have " , len: -1); |
163 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
164 | text: "italic" , len: -1, |
165 | first_tag_name: "italic" , NULL); |
166 | gtk_text_buffer_insert (buffer, iter: &iter, text: ", " , len: -1); |
167 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
168 | text: "bold" , len: -1, |
169 | first_tag_name: "bold" , NULL); |
170 | gtk_text_buffer_insert (buffer, iter: &iter, text: ", or " , len: -1); |
171 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
172 | text: "monospace (typewriter)" , len: -1, |
173 | first_tag_name: "monospace" , NULL); |
174 | gtk_text_buffer_insert (buffer, iter: &iter, text: ", or " , len: -1); |
175 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
176 | text: "big" , len: -1, |
177 | first_tag_name: "big" , NULL); |
178 | gtk_text_buffer_insert (buffer, iter: &iter, text: " text. " , len: -1); |
179 | gtk_text_buffer_insert (buffer, iter: &iter, |
180 | text: "It's best not to hardcode specific text sizes; you can use relative " |
181 | "sizes as with CSS, such as " , len: -1); |
182 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
183 | text: "xx-small" , len: -1, |
184 | first_tag_name: "xx-small" , NULL); |
185 | gtk_text_buffer_insert (buffer, iter: &iter, text: " or " , len: -1); |
186 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
187 | text: "x-large" , len: -1, |
188 | first_tag_name: "x-large" , NULL); |
189 | gtk_text_buffer_insert (buffer, iter: &iter, |
190 | text: " to ensure that your program properly adapts if the user changes the " |
191 | "default font size.\n\n" , len: -1); |
192 | |
193 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, text: "Colors. " , len: -1, |
194 | first_tag_name: "heading" , NULL); |
195 | |
196 | gtk_text_buffer_insert (buffer, iter: &iter, text: "Colors such as " , len: -1); |
197 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
198 | text: "a blue foreground" , len: -1, |
199 | first_tag_name: "blue_foreground" , NULL); |
200 | gtk_text_buffer_insert (buffer, iter: &iter, text: " or " , len: -1); |
201 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
202 | text: "a red background" , len: -1, |
203 | first_tag_name: "red_background" , NULL); |
204 | gtk_text_buffer_insert (buffer, iter: &iter, text: " or even " , len: -1); |
205 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
206 | text: "a blue foreground on red background" , len: -1, |
207 | first_tag_name: "blue_foreground" , |
208 | "red_background" , |
209 | NULL); |
210 | gtk_text_buffer_insert (buffer, iter: &iter, text: " (select that to read it) can be used.\n\n" , len: -1); |
211 | |
212 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
213 | text: "Underline, strikethrough, and rise. " , len: -1, |
214 | first_tag_name: "heading" , NULL); |
215 | |
216 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
217 | text: "Strikethrough" , len: -1, |
218 | first_tag_name: "strikethrough" , NULL); |
219 | gtk_text_buffer_insert (buffer, iter: &iter, text: ", " , len: -1); |
220 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
221 | text: "underline" , len: -1, |
222 | first_tag_name: "underline" , NULL); |
223 | gtk_text_buffer_insert (buffer, iter: &iter, text: ", " , len: -1); |
224 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
225 | text: "double underline" , len: -1, |
226 | first_tag_name: "double_underline" , NULL); |
227 | gtk_text_buffer_insert (buffer, iter: &iter, text: ", " , len: -1); |
228 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
229 | text: "superscript" , len: -1, |
230 | first_tag_name: "superscript" , NULL); |
231 | gtk_text_buffer_insert (buffer, iter: &iter, text: ", and " , len: -1); |
232 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
233 | text: "subscript" , len: -1, |
234 | first_tag_name: "subscript" , NULL); |
235 | gtk_text_buffer_insert (buffer, iter: &iter, text: " are all supported.\n\n" , len: -1); |
236 | |
237 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, text: "Images. " , len: -1, |
238 | first_tag_name: "heading" , NULL); |
239 | |
240 | gtk_text_buffer_insert (buffer, iter: &iter, text: "The buffer can have images in it: " , len: -1); |
241 | gtk_text_buffer_insert_paintable (buffer, iter: &iter, paintable: GDK_PAINTABLE (ptr: icon)); |
242 | gtk_text_buffer_insert_paintable (buffer, iter: &iter, paintable: GDK_PAINTABLE (ptr: icon)); |
243 | |
244 | gtk_text_buffer_insert_paintable (buffer, iter: &iter, paintable: nuclear); |
245 | |
246 | gtk_text_buffer_insert (buffer, iter: &iter, text: " for example.\n\n" , len: -1); |
247 | |
248 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, text: "Spacing. " , len: -1, |
249 | first_tag_name: "heading" , NULL); |
250 | |
251 | gtk_text_buffer_insert (buffer, iter: &iter, |
252 | text: "You can adjust the amount of space before each line.\n" , len: -1); |
253 | |
254 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
255 | text: "This line has a whole lot of space before it.\n" , len: -1, |
256 | first_tag_name: "big_gap_before_line" , "wide_margins" , NULL); |
257 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
258 | text: "You can also adjust the amount of space after each line; " |
259 | "this line has a whole lot of space after it.\n" , len: -1, |
260 | first_tag_name: "big_gap_after_line" , "wide_margins" , NULL); |
261 | |
262 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
263 | text: "You can also adjust the amount of space between wrapped lines; " |
264 | "this line has extra space between each wrapped line in the same " |
265 | "paragraph. To show off wrapping, some filler text: the quick " |
266 | "brown fox jumped over the lazy dog. Blah blah blah blah blah " |
267 | "blah blah blah blah.\n" , len: -1, |
268 | first_tag_name: "double_spaced_line" , "wide_margins" , NULL); |
269 | |
270 | gtk_text_buffer_insert (buffer, iter: &iter, |
271 | text: "Also note that those lines have extra-wide margins.\n\n" , len: -1); |
272 | |
273 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
274 | text: "Editability. " , len: -1, |
275 | first_tag_name: "heading" , NULL); |
276 | |
277 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
278 | text: "This line is 'locked down' and can't be edited by the user - just " |
279 | "try it! You can't delete this line.\n\n" , len: -1, |
280 | first_tag_name: "not_editable" , NULL); |
281 | |
282 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
283 | text: "Wrapping. " , len: -1, |
284 | first_tag_name: "heading" , NULL); |
285 | |
286 | gtk_text_buffer_insert (buffer, iter: &iter, |
287 | text: "This line (and most of the others in this buffer) is word-wrapped, " |
288 | "using the proper Unicode algorithm. Word wrap should work in all " |
289 | "scripts and languages that GTK supports. Let's make this a long " |
290 | "paragraph to demonstrate: blah blah blah blah blah blah blah blah " |
291 | "blah blah blah blah blah blah blah blah blah blah blah\n\n" , len: -1); |
292 | |
293 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
294 | text: "This line has character-based wrapping, and can wrap between any two " |
295 | "character glyphs. Let's make this a long paragraph to demonstrate: " |
296 | "blah blah blah blah blah blah blah blah blah blah blah blah blah blah " |
297 | "blah blah blah blah blah\n\n" , len: -1, first_tag_name: "char_wrap" , NULL); |
298 | |
299 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
300 | text: "This line has all wrapping turned off, so it makes the horizontal " |
301 | "scrollbar appear.\n\n\n" , len: -1, first_tag_name: "no_wrap" , NULL); |
302 | |
303 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
304 | text: "Justification. " , len: -1, |
305 | first_tag_name: "heading" , NULL); |
306 | |
307 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
308 | text: "\nThis line has center justification.\n" , len: -1, |
309 | first_tag_name: "center" , NULL); |
310 | |
311 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
312 | text: "This line has right justification.\n" , len: -1, |
313 | first_tag_name: "right_justify" , NULL); |
314 | |
315 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
316 | text: "\nThis line has big wide margins. Text text text text text text text " |
317 | "text text text text text text text text text text text text text text " |
318 | "text text text text text text text text text text text text text text " |
319 | "text.\n" , len: -1, first_tag_name: "wide_margins" , NULL); |
320 | |
321 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
322 | text: "Internationalization. " , len: -1, |
323 | first_tag_name: "heading" , NULL); |
324 | |
325 | gtk_text_buffer_insert (buffer, iter: &iter, |
326 | text: "You can put all sorts of Unicode text in the buffer.\n\nGerman " |
327 | "(Deutsch S\303\274d) Gr\303\274\303\237 Gott\nGreek " |
328 | "(\316\225\316\273\316\273\316\267\316\275\316\271\316\272\316\254) " |
329 | "\316\223\316\265\316\271\316\254 \317\203\316\261\317\202\nHebrew " |
330 | "\327\251\327\234\327\225\327\235\nJapanese " |
331 | "(\346\227\245\346\234\254\350\252\236)\n\nThe widget properly handles " |
332 | "bidirectional text, word wrapping, DOS/UNIX/Unicode paragraph separators, " |
333 | "grapheme boundaries, and so on using the Pango internationalization " |
334 | "framework.\n" , len: -1); |
335 | |
336 | gtk_text_buffer_insert (buffer, iter: &iter, |
337 | text: "Here's a word-wrapped quote in a right-to-left language:\n" , len: -1); |
338 | gtk_text_buffer_insert_with_tags_by_name (buffer, iter: &iter, |
339 | text: "\331\210\331\202\330\257 \330\250\330\257\330\243 " |
340 | "\330\253\331\204\330\247\330\253 \331\205\331\206 " |
341 | "\330\243\331\203\330\253\330\261 \330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 " |
342 | "\330\252\331\202\330\257\331\205\330\247 \331\201\331\212 " |
343 | "\330\264\330\250\331\203\330\251 \330\247\331\203\330\263\331\212\331\210\331\206 " |
344 | "\330\250\330\261\330\247\331\205\330\254\331\207\330\247 " |
345 | "\331\203\331\205\331\206\330\270\331\205\330\247\330\252 " |
346 | "\331\204\330\247 \330\252\330\263\330\271\331\211 \331\204\331\204\330\261\330\250\330\255\330\214 " |
347 | "\330\253\331\205 \330\252\330\255\331\210\331\204\330\252 " |
348 | "\331\201\331\212 \330\247\331\204\330\263\331\206\331\210\330\247\330\252 " |
349 | "\330\247\331\204\330\256\331\205\330\263 \330\247\331\204\331\205\330\247\330\266\331\212\330\251 " |
350 | "\330\245\331\204\331\211 \331\205\330\244\330\263\330\263\330\247\330\252 " |
351 | "\331\205\330\247\331\204\331\212\330\251 \331\205\331\206\330\270\331\205\330\251\330\214 " |
352 | "\331\210\330\250\330\247\330\252\330\252 \330\254\330\262\330\241\330\247 " |
353 | "\331\205\331\206 \330\247\331\204\331\206\330\270\330\247\331\205 " |
354 | "\330\247\331\204\331\205\330\247\331\204\331\212 \331\201\331\212 " |
355 | "\330\250\331\204\330\257\330\247\331\206\331\207\330\247\330\214 " |
356 | "\331\210\331\204\331\203\331\206\331\207\330\247 \330\252\330\252\330\256\330\265\330\265 " |
357 | "\331\201\331\212 \330\256\330\257\331\205\330\251 \331\202\330\267\330\247\330\271 " |
358 | "\330\247\331\204\331\205\330\264\330\261\331\210\330\271\330\247\330\252 " |
359 | "\330\247\331\204\330\265\330\272\331\212\330\261\330\251. \331\210\330\243\330\255\330\257 " |
360 | "\330\243\331\203\330\253\330\261 \331\207\330\260\331\207 " |
361 | "\330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 " |
362 | "\331\206\330\254\330\247\330\255\330\247 \331\207\331\210 " |
363 | "\302\273\330\250\330\247\331\206\331\203\331\210\330\263\331\210\331\204\302\253 " |
364 | "\331\201\331\212 \330\250\331\210\331\204\331\212\331\201\331\212\330\247.\n\n" , len: -1, |
365 | first_tag_name: "rtl_quote" , NULL); |
366 | |
367 | gtk_text_buffer_insert (buffer, iter: &iter, |
368 | text: "You can put widgets in the buffer: Here's a button: " , len: -1); |
369 | gtk_text_buffer_create_child_anchor (buffer, iter: &iter); |
370 | gtk_text_buffer_insert (buffer, iter: &iter, text: " and a menu: " , len: -1); |
371 | gtk_text_buffer_create_child_anchor (buffer, iter: &iter); |
372 | gtk_text_buffer_insert (buffer, iter: &iter, text: " and a scale: " , len: -1); |
373 | gtk_text_buffer_create_child_anchor (buffer, iter: &iter); |
374 | gtk_text_buffer_insert (buffer, iter: &iter, text: " finally a text entry: " , len: -1); |
375 | gtk_text_buffer_create_child_anchor (buffer, iter: &iter); |
376 | gtk_text_buffer_insert (buffer, iter: &iter, text: ".\n" , len: -1); |
377 | |
378 | gtk_text_buffer_insert (buffer, iter: &iter, |
379 | text: "\n\nThis demo doesn't demonstrate all the GtkTextBuffer features; " |
380 | "it leaves out, for example: invisible/hidden text, tab stops, " |
381 | "application-drawn areas on the sides of the widget for displaying " |
382 | "breakpoints and such..." , len: -1); |
383 | |
384 | /* Apply word_wrap tag to whole buffer */ |
385 | gtk_text_buffer_get_bounds (buffer, start: &start, end: &end); |
386 | gtk_text_buffer_apply_tag_by_name (buffer, name: "word_wrap" , start: &start, end: &end); |
387 | |
388 | gtk_text_buffer_end_irreversible_action (buffer); |
389 | |
390 | g_object_unref (object: icon); |
391 | g_object_unref (object: nuclear); |
392 | } |
393 | |
394 | static gboolean |
395 | find_anchor (GtkTextIter *iter) |
396 | { |
397 | while (gtk_text_iter_forward_char (iter)) |
398 | { |
399 | if (gtk_text_iter_get_child_anchor (iter)) |
400 | return TRUE; |
401 | } |
402 | return FALSE; |
403 | } |
404 | |
405 | static void |
406 | attach_widgets (GtkTextView *text_view) |
407 | { |
408 | GtkTextIter iter; |
409 | GtkTextBuffer *buffer; |
410 | int i; |
411 | |
412 | buffer = gtk_text_view_get_buffer (text_view); |
413 | |
414 | gtk_text_buffer_get_start_iter (buffer, iter: &iter); |
415 | |
416 | i = 0; |
417 | while (find_anchor (iter: &iter)) |
418 | { |
419 | GtkTextChildAnchor *anchor; |
420 | GtkWidget *widget; |
421 | |
422 | anchor = gtk_text_iter_get_child_anchor (iter: &iter); |
423 | |
424 | if (i == 0) |
425 | { |
426 | widget = gtk_button_new_with_label (label: "Click Me" ); |
427 | |
428 | g_signal_connect (widget, "clicked" , |
429 | G_CALLBACK (easter_egg_callback), |
430 | NULL); |
431 | } |
432 | else if (i == 1) |
433 | { |
434 | widget = gtk_combo_box_text_new (); |
435 | |
436 | gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), text: "Option 1" ); |
437 | gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), text: "Option 2" ); |
438 | gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), text: "Option 3" ); |
439 | } |
440 | else if (i == 2) |
441 | { |
442 | widget = gtk_scale_new (orientation: GTK_ORIENTATION_HORIZONTAL, NULL); |
443 | gtk_range_set_range (GTK_RANGE (widget), min: 0, max: 100); |
444 | gtk_widget_set_size_request (widget, width: 70, height: -1); |
445 | } |
446 | else if (i == 3) |
447 | { |
448 | widget = gtk_entry_new (); |
449 | } |
450 | else |
451 | { |
452 | widget = NULL; /* avoids a compiler warning */ |
453 | g_assert_not_reached (); |
454 | } |
455 | |
456 | gtk_text_view_add_child_at_anchor (text_view, |
457 | child: widget, |
458 | anchor); |
459 | |
460 | ++i; |
461 | } |
462 | } |
463 | |
464 | GtkWidget * |
465 | do_textview (GtkWidget *do_widget) |
466 | { |
467 | static GtkWidget *window = NULL; |
468 | |
469 | if (!window) |
470 | { |
471 | GtkWidget *vpaned; |
472 | GtkWidget *view1; |
473 | GtkWidget *view2; |
474 | GtkWidget *sw; |
475 | GtkTextBuffer *buffer; |
476 | |
477 | window = gtk_window_new (); |
478 | gtk_window_set_display (GTK_WINDOW (window), |
479 | display: gtk_widget_get_display (widget: do_widget)); |
480 | gtk_window_set_default_size (GTK_WINDOW (window), width: 450, height: 450); |
481 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window); |
482 | |
483 | gtk_window_set_title (GTK_WINDOW (window), title: "Multiple Views" ); |
484 | |
485 | vpaned = gtk_paned_new (orientation: GTK_ORIENTATION_VERTICAL); |
486 | gtk_window_set_child (GTK_WINDOW (window), child: vpaned); |
487 | |
488 | /* For convenience, we just use the autocreated buffer from |
489 | * the first text view; you could also create the buffer |
490 | * by itself with gtk_text_buffer_new(), then later create |
491 | * a view widget. |
492 | */ |
493 | view1 = gtk_text_view_new (); |
494 | buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view1)); |
495 | view2 = gtk_text_view_new_with_buffer (buffer); |
496 | |
497 | sw = gtk_scrolled_window_new (); |
498 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), |
499 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
500 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
501 | gtk_paned_set_start_child (GTK_PANED (vpaned), child: sw); |
502 | gtk_paned_set_resize_start_child (GTK_PANED (vpaned), FALSE); |
503 | gtk_paned_set_shrink_start_child (GTK_PANED (vpaned), TRUE); |
504 | |
505 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: view1); |
506 | |
507 | sw = gtk_scrolled_window_new (); |
508 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), |
509 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
510 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
511 | gtk_paned_set_end_child (GTK_PANED (vpaned), child: sw); |
512 | gtk_paned_set_resize_end_child (GTK_PANED (vpaned), TRUE); |
513 | gtk_paned_set_shrink_end_child (GTK_PANED (vpaned), TRUE); |
514 | |
515 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: view2); |
516 | |
517 | create_tags (buffer); |
518 | insert_text (GTK_TEXT_VIEW (view1)); |
519 | |
520 | attach_widgets (GTK_TEXT_VIEW (view1)); |
521 | attach_widgets (GTK_TEXT_VIEW (view2)); |
522 | } |
523 | |
524 | if (!gtk_widget_get_visible (widget: window)) |
525 | { |
526 | gtk_widget_show (widget: window); |
527 | } |
528 | else |
529 | { |
530 | gtk_window_destroy (GTK_WINDOW (window)); |
531 | window = NULL; |
532 | } |
533 | |
534 | return window; |
535 | } |
536 | |
537 | static void |
538 | recursive_attach_view (int depth, |
539 | GtkTextView *view, |
540 | GtkTextChildAnchor *anchor) |
541 | { |
542 | GtkWidget *child_view, *frame; |
543 | |
544 | if (depth > 4) |
545 | return; |
546 | |
547 | child_view = gtk_text_view_new_with_buffer (buffer: gtk_text_view_get_buffer (text_view: view)); |
548 | gtk_widget_set_size_request (widget: child_view, width: 260 - 20 * depth, height: -1); |
549 | |
550 | /* Frame is to add a black border around each child view */ |
551 | frame = gtk_frame_new (NULL); |
552 | gtk_frame_set_child (GTK_FRAME (frame), child: child_view); |
553 | |
554 | gtk_text_view_add_child_at_anchor (text_view: view, child: frame, anchor); |
555 | |
556 | recursive_attach_view (depth: depth + 1, GTK_TEXT_VIEW (child_view), anchor); |
557 | } |
558 | |
559 | static void |
560 | easter_egg_callback (GtkWidget *button, |
561 | gpointer data) |
562 | { |
563 | static GtkWidget *window = NULL; |
564 | gpointer window_ptr; |
565 | GtkTextBuffer *buffer; |
566 | GtkWidget *view; |
567 | GtkTextIter iter; |
568 | GtkTextChildAnchor *anchor; |
569 | GtkWidget *sw; |
570 | |
571 | if (window) |
572 | { |
573 | gtk_window_present (GTK_WINDOW (window)); |
574 | return; |
575 | } |
576 | |
577 | buffer = gtk_text_buffer_new (NULL); |
578 | |
579 | gtk_text_buffer_get_start_iter (buffer, iter: &iter); |
580 | |
581 | gtk_text_buffer_insert (buffer, iter: &iter, |
582 | text: "This buffer is shared by a set of nested text views.\n Nested view:\n" , len: -1); |
583 | anchor = gtk_text_buffer_create_child_anchor (buffer, iter: &iter); |
584 | gtk_text_buffer_insert (buffer, iter: &iter, |
585 | text: "\nDon't do this in real applications, please.\n" , len: -1); |
586 | |
587 | view = gtk_text_view_new_with_buffer (buffer); |
588 | |
589 | recursive_attach_view (depth: 0, GTK_TEXT_VIEW (view), anchor); |
590 | |
591 | g_object_unref (object: buffer); |
592 | |
593 | window = gtk_window_new (); |
594 | gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (gtk_widget_get_root (button))); |
595 | gtk_window_set_modal (GTK_WINDOW (window), TRUE); |
596 | sw = gtk_scrolled_window_new (); |
597 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), |
598 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
599 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
600 | |
601 | gtk_window_set_child (GTK_WINDOW (window), child: sw); |
602 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: view); |
603 | |
604 | window_ptr = &window; |
605 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: window_ptr); |
606 | |
607 | gtk_window_set_default_size (GTK_WINDOW (window), width: 300, height: 400); |
608 | |
609 | gtk_widget_show (widget: window); |
610 | } |
611 | |