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 }