1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * gtkD is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with gtkD; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
17  */
18 
19 module TTextView;
20 
21 private import gtk.Window;
22 
23 private import gtk.Widget;
24 private import gtk.TextView;
25 private import gtk.TextBuffer;
26 private import gtk.TextIter;
27 private import gtk.VPaned;
28 private import gtk.ScrolledWindow;
29 private import gtk.TextChildAnchor;
30 private import gtk.Button;
31 private import gtk.Menu;
32 private import gtk.MenuItem;
33 private import gtk.HScale;
34 private import gtk.Image;
35 private import gtk.Entry;
36 
37 private import gdk.Pixbuf;
38 
39 private import gtk.ComboBoxText;
40 
41 private import glib.GException;
42 
43 private import std.stdio;
44 
45 /**
46  * reproduces the gtk-demo TextView
47  * \bug the output shows erros like (DUITest.exe:5012): GLib-GObject-WARNING **: [Invalid UTF-8] gobject.c:882: object class `GtkTextTag' has no property named `l┌E'
48  */
49 
50 public:
51 class TTextView : Window
52 {
53 	TextView view1;
54 	TextBuffer buffer;
55 	TextView view2;
56 
57 	/**
58 	 * ctor. must reactivate the constructor name change loby
59 	 */
60 	this()
61 	{
62 		super("TextView");
63 		setDefaultSize(450,450);
64 		setBorderWidth(0);
65 
66 		createTextViews();
67 
68 		setupWidgets();
69 
70 		createTags(buffer);
71 		insertText(buffer);
72 
73 		attachWidgets(view1);
74 		attachWidgets(view2);
75 
76 		showAll();
77 	}
78 
79 //	bit windowDeleteCallback(Window window, Event event)
80 //	{
81 //		return false;
82 //	}
83 //
84 //	bit windowDestroyCallback(Window window, Event event)
85 //	{
86 //		writeln("TTextView windowDestroyCallback");
87 //		return false;
88 //	}
89 
90 	/**
91 	 * creates the text view and buffer to use
92 	 */
93 	void createTextViews()
94 	{
95 		view1 = new TextView();
96 		buffer = view1.getBuffer();
97 		view2 = new TextView(buffer);
98 	}
99 
100 	/**
101 	 * sets up the widgets ot this test
102 	 */
103 	void setupWidgets()
104 	{
105 		VPaned vPaned = new VPaned();
106 		vPaned.setBorderWidth(5);
107 		add(vPaned);
108 
109 		ScrolledWindow sw = new ScrolledWindow(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
110 		sw.add(view1);
111 		vPaned.add1(sw);
112 		sw = new ScrolledWindow(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
113 		sw.add(view2);
114 		vPaned.add2(sw);
115 	}
116 
117 	/**
118 	 * Creates all the text tags to use
119 	 * @param buffer the TextBuffer
120 	 */
121 	void createTags(TextBuffer buffer)
122 	{
123 		/* Create a bunch of tags. Note that it's also possible to
124 		* create tags with gtk_text_tag_new() then add them to the
125 		* tag table for the buffer, gtk_text_buffer_create_tag() is
126 		* just a convenience function. Also note that you don't have
127 		* to give tags a name; pass NULL for the name to create an
128 		* anonymous tag.
129 		*
130 		* In any real app, another useful optimization would be to create
131 		* a GtkTextTagTable in advance, and reuse the same tag table for
132 		* all the buffers with the same tag set, instead of creating
133 		* new copies of the same tags for every buffer.
134 		*
135 		* Tags are assigned default priorities in order of addition to the
136 		* tag table.	 That is, tags created later that affect the same text
137 		* property affected by an earlier tag will override the earlier
138 		* tag.  You can modify tag priorities with
139 		* gtk_text_tag_set_priority().
140 		*/
141 
142 		buffer.createTag("heading",
143 						"weight", PangoWeight.BOLD,
144 						"size", 15 * PANGO_SCALE);
145     	buffer.createTag("italic",
146     					"style", cast(int)PangoStyle.ITALIC);
147 
148 		buffer.createTag("bold",
149 			      "weight", cast(int)PangoWeight.BOLD);
150 
151 		buffer.createTag("big",
152 			      /* points times the PANGO_SCALE factor */
153 			      "size", 20 * PANGO_SCALE);
154 
155 		buffer.createTag("xx-small",
156 			      "scale", PANGO_SCALE_XX_SMALL);
157 
158 		buffer.createTag("x-large",
159 			      "scale", PANGO_SCALE_X_LARGE);
160 
161 		buffer.createTag("monospace",
162 			      "family", "monospace");
163 
164 		buffer.createTag("blue_foreground",
165 			      "foreground", "blue");
166 
167 		buffer.createTag("red_background",
168 			      "background", "red");
169 
170 		buffer.createTag("big_gap_before_line",
171 			      "pixels_above_lines", 30);
172 
173 		buffer.createTag("big_gap_after_line",
174 			      "pixels_below_lines", 30);
175 
176 		buffer.createTag("double_spaced_line",
177 			      "pixels_inside_wrap", 10);
178 
179 		buffer.createTag("not_editable",
180 			      "editable", cast(int)false);
181 
182 		buffer.createTag("word_wrap",
183 			      "wrap_mode", cast(int)WrapMode.WORD);
184 
185 		buffer.createTag("char_wrap",
186 			      "wrap_mode", cast(int)WrapMode.CHAR);
187 
188 		buffer.createTag("no_wrap",
189 			      "wrap_mode", cast(int)WrapMode.NONE);
190 
191 		buffer.createTag("center",
192 			      "justification", cast(int)Justification.CENTER);
193 
194 		buffer.createTag("right_justify",
195 			      "justification", cast(int)Justification.RIGHT);
196 
197 		buffer.createTag("wide_margins",
198 			      "left_margin", 50, "right_margin", 50);
199 
200 		buffer.createTag("strikethrough",
201 			      "strikethrough", cast(int)true);
202 
203 		buffer.createTag("underline",
204 			      "underline", cast(int)PangoUnderline.SINGLE);
205 
206 		buffer.createTag("double_underline",
207 			      "underline", cast(int)PangoUnderline.DOUBLE);
208 
209 		buffer.createTag("superscript",
210 			      "rise", 10 * PANGO_SCALE,	  /* 10 pixels */
211 			      "size", 8 * PANGO_SCALE);	  /* 8 points */
212 
213 		buffer.createTag("subscript",
214 			      "rise", -10 * PANGO_SCALE,   /* 10 pixels */
215 			      "size", 8 * PANGO_SCALE);	   /* 8 points */
216 
217 
218 		buffer.createTag("rtl_quote",
219 			      "wrap_mode", WrapMode.WORD,
220 			      "direction", TextDirection.RTL,
221 			      "indent", 30,
222 			      "left_margin", 20,
223 			      "right_margin", 20);
224 
225 	}
226 	/**
227 	 * Inserts all the test text into the buffer
228 	 * @param buffer the TextBuffer
229 	 */
230 	void insertText(TextBuffer buffer)
231 	{
232 		//version(Tango) {} else
233 		{
234 		TextIter iter = new TextIter();
235 		TextIter start = new TextIter();
236 		TextIter end = new TextIter();
237 		Pixbuf pixbuf;
238 		Pixbuf scaled;
239 		TextChildAnchor anchor;
240 		string filename;
241 
242 		/* demo_find_file() looks in the the current directory first,
243 		* so you can run gtk-demo without installing GTK, then looks
244 		* in the location where the file is installed.
245 		*/
246 
247 		try
248 		{
249 			pixbuf = new Pixbuf("images/gtk-logo-rgb.gif");
250 
251 			scaled = pixbuf.scaleSimple(32, 32, InterpType.BILINEAR);
252 			pixbuf = pixbuf.scaleSimple(38, 38, InterpType.BILINEAR);
253 		}
254 		catch (Exception)
255 		{
256 			version(Tango) Stdout("Failed to load image file gtk-logo-rgb.gif").newline;
257 			else writef("Failed to load image file gtk-logo-rgb.gif\n");
258 		}
259 
260 		/* get start of buffer; each insertion will revalidate the
261 		* iterator to point to just after the inserted text.
262 		*/
263 
264 		buffer.getIterAtOffset(iter, 0);
265 
266 		buffer.insert(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");
267 
268 		buffer.insertWithTagsByName(iter, "Font styles. ","heading");
269 
270 		buffer.insert(iter, "For example, you can have ");
271 		buffer.insertWithTagsByName(iter, "italic", "italic");
272 		buffer.insert(iter, ", ");
273 		buffer.insertWithTagsByName(iter, "bold", "bold");
274 		buffer.insert(iter, ", or ");
275 		buffer.insertWithTagsByName(iter, "monospace (typewriter)", "monospace");
276 		buffer.insert(iter, ", or ");
277 		buffer.insertWithTagsByName(iter, "big", "big");
278 		buffer.insert(iter, " text. ");
279 		buffer.insert(iter, "It's best not to hardcode specific text sizes; you can use relative sizes as with CSS, such as ");
280 		buffer.insertWithTagsByName(iter, "xx-small", "xx-small");
281 		buffer.insert(iter, " or ");
282 		buffer.insertWithTagsByName(iter, "x-large", "x-large");
283 		buffer.insert(iter, " to ensure that your program properly adapts if the user changes the default font size.\n\n");
284 
285 		buffer.insertWithTagsByName(iter, "Colors. ", "heading");
286 
287 		buffer.insert(iter, "Colors such as ");
288 		buffer.insertWithTagsByName(iter, "a blue foreground", "blue_foreground");
289 		buffer.insert(iter, " or ");
290 		buffer.insertWithTagsByName(iter, "a red background", "red_background");
291 		buffer.insert(iter, " can be used.\n\n");
292 
293 		buffer.insertWithTagsByName(iter, "Underline, strikethrough, and rise. ", "heading");
294 
295 		buffer.insertWithTagsByName(iter, "Strikethrough", "strikethrough");
296 		buffer.insert(iter, ", ");
297 		buffer.insertWithTagsByName(iter, "underline", "underline");
298 		buffer.insert(iter, ", ");
299 		buffer.insertWithTagsByName(iter, "double underline", "double_underline");
300 		buffer.insert(iter, ", ");
301 		buffer.insertWithTagsByName(iter, "superscript", "superscript");
302 		buffer.insert(iter, ", and ");
303 		buffer.insertWithTagsByName(iter, "subscript", "subscript");
304 		buffer.insert(iter, " are all supported.\n\n");
305 
306 		buffer.insertWithTagsByName(iter, "Images. ", "heading");
307 
308 		buffer.insert(iter, "The buffer can have images in it: ");
309 		if ( pixbuf !is  null )
310 		{
311 			buffer.insertPixbuf(iter, scaled);
312 			buffer.insertPixbuf(iter, pixbuf);
313 			buffer.insertPixbuf(iter, scaled);
314 		}
315 		else
316 		{
317 			buffer.insert(iter,"Sorry can't find the images");
318 		}
319 		buffer.insert(iter, " for example.\n\n");
320 
321 		buffer.insertWithTagsByName(iter, "Spacing. ", "heading");
322 
323 		buffer.insert(iter, "You can adjust the amount of space before each line.\n");
324 
325 		buffer.insertWithTagsByName(iter, "This line has a whole lot of space before it.\n",
326 					    "big_gap_before_line", "wide_margins");
327 		buffer.insertWithTagsByName(iter,
328 					    "You can also adjust the amount of space after each line; this line has a whole lot of space after it.\n",
329 					    "big_gap_after_line", "wide_margins");
330 
331 		buffer.insertWithTagsByName(iter,
332 					    "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",
333 					    "double_spaced_line", "wide_margins");
334 
335 		buffer.insert(iter, "Also note that those lines have extra-wide margins.\n\n");
336 
337 		buffer.insertWithTagsByName(iter, "Editability. ", "heading");
338 
339 		buffer.insertWithTagsByName(iter,
340 					    "This line is 'locked down' and can't be edited by the user - just try it! You can't delete this line.\n\n",
341 					    "not_editable");
342 
343 		buffer.insertWithTagsByName(iter, "Wrapping. ", "heading");
344 
345 		buffer.insert(iter,
346 			  "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");
347 
348 		buffer.insertWithTagsByName(iter,
349 					    "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",
350 					    "char_wrap");
351 
352 		buffer.insertWithTagsByName(iter,
353 					    "This line has all wrapping turned off, so it makes the horizontal scrollbar appear.\n\n\n",
354 					    "no_wrap");
355 
356 		buffer.insertWithTagsByName(iter, "Justification. ", "heading");
357 
358 		buffer.insertWithTagsByName(iter,
359 					    "\nThis line has center justification.\n", "center");
360 
361 		buffer.insertWithTagsByName(iter,
362 					    "This line has right justification.\n", "right_justify");
363 
364 		buffer.insertWithTagsByName(iter,
365 					    "\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",
366 					    "wide_margins");
367 
368 		buffer.insertWithTagsByName(iter, "Internationalization. ", "heading");
369 
370 		buffer.insert(iter,
371 			  "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");
372 
373 		buffer.insert(iter, "Here's a word-wrapped quote in a right-to-left language:\n");
374 		buffer.insertWithTagsByName(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",
375 						"rtl_quote");
376 
377 		buffer.insert(iter, "You can put widgets in the buffer: Here's a button: ");
378 		anchor = buffer.createChildAnchor(iter);
379 		buffer.insert(iter, " and a menu: ");
380 		anchor = buffer.createChildAnchor(iter);
381 		buffer.insert(iter, " and a scale: ");
382 		anchor = buffer.createChildAnchor(iter);
383 		buffer.insert(iter, " and an animation: ");
384 		anchor = buffer.createChildAnchor(iter);
385 		buffer.insert(iter, " finally a text entry: ");
386 		anchor = buffer.createChildAnchor(iter);
387 		buffer.insert(iter, ".\n");
388 
389 		buffer.insert(iter, "\n\nThis demo doesn't demonstrate all the GtkTextBuffer features; it leaves out, for example: invisible/hidden text (doesn't work in GTK 2, but planned), tab stops, application-drawn areas on the sides of the widget for displaying breakpoints and such...");
390 
391     	/* Apply word_wrap tag to whole buffer */
392 		buffer.getBounds(start, end);
393 		buffer.applyTagByName("word_wrap", start, end);
394 		}
395 	}
396 
397 	/**
398 	 * Attaches all test widgets to the text view
399 	 * @param view the TextView
400 	 */
401 	void attachWidgets(TextView view)
402 	{
403 		TextIter iter = new TextIter();
404 		TextBuffer buffer;
405 		int i;
406 
407 		buffer = view.getBuffer();
408 
409     	buffer.getStartIter(iter);
410 
411 		i = 0;
412 
413 		while (findAnchor(iter))
414 		{
415 			TextChildAnchor anchor;// = new TextChildAnchor();
416 			Widget widget;
417 			anchor = iter.getChildAnchor();
418 
419 			if (i == 0)
420 			{
421 				Button button = new Button("Click Me");
422 				widget = button;
423 			}
424 			else if (i == 1)
425         	{
426 
427 				ComboBoxText comboBox = new ComboBoxText();
428 				comboBox.appendText("Option 1");
429 				comboBox.appendText("Option 2");
430 				comboBox.appendText("Option 3");
431 				widget = comboBox;
432 			}
433 			else if (i == 2)
434 			{
435 				HScale hScale = new HScale(0.0,100.0,5.0);
436 				hScale.setSizeRequest(70, -1);
437 				widget = hScale;
438 			}
439 			else if (i == 3)
440 			{
441 				Image image = new Image("images/floppybuddy.gif");
442 				widget = image;
443 			}
444 			else if (i == 4)
445 			{
446 				widget = new Entry();
447 			}
448 			else
449 			{
450 				widget = null;
451 				//g_assert_not_reached ();
452 			}
453 
454 			if ( widget !is  null )
455 			{
456 				view.addChildAtAnchor(widget,anchor);
457 			}
458 
459 			++i;
460 		}
461 	}
462 
463 	bool findAnchor (TextIter iter)
464 	{
465 		while (iter.forwardChar())
466 		{
467 			if (iter.getChildAnchor() !is  null ) //gtk_text_iter_get_child_anchor (iter))
468 			{
469 				return true;
470 			}
471 		}
472 		return false;
473 	}
474 
475 }