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