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