1 /** 2 * Widget module. 3 * 4 * License: 5 * MIT. See LICENSE for full details. 6 */ 7 module tkd.widget.text; 8 9 /** 10 * Imports. 11 */ 12 import std.conv; 13 import tkd.element.uielement; 14 import tkd.image.image; 15 import tkd.widget.common.border; 16 import tkd.widget.common.height; 17 import tkd.widget.common.relief; 18 import tkd.widget.common.width; 19 import tkd.widget.common.xscrollcommand; 20 import tkd.widget.common.xview; 21 import tkd.widget.common.yscrollcommand; 22 import tkd.widget.common.yview; 23 import tkd.widget.textwrapmode; 24 import tkd.widget.widget; 25 26 /** 27 * A text widget displays one or more lines of text and allows that text to be 28 * edited. Text widgets support embedded widgets or embedded images. 29 * 30 * Example: 31 * --- 32 * auto text = new Text() 33 * .appendText("Text") 34 * .pack(); 35 * --- 36 * 37 * Common_Commands: 38 * These are injected common commands that can also be used with this widget. 39 * $(P 40 * $(LINK2 ./common/border.html, Border) $(BR) 41 * $(LINK2 ./common/height.html, Height) $(BR) 42 * $(LINK2 ./common/relief.html, Relief) $(BR) 43 * $(LINK2 ./common/width.html, Width) $(BR) 44 * $(LINK2 ./common/xscrollcommand.html, XScrollCommand) $(BR) 45 * $(LINK2 ./common/xview.html, XView) $(BR) 46 * $(LINK2 ./common/yscrollcommand.html, YScrollCommand) $(BR) 47 * $(LINK2 ./common/yview.html, YView) $(BR) 48 * ) 49 * 50 * Additional_Events: 51 * Additional events that can also be bound to using the $(LINK2 ../element/uielement.html#UiElement.bind, bind) method. 52 * $(P 53 * <<Clear>>, 54 * <<Copy>>, 55 * <<Cut>>, 56 * <<Modified>>, 57 * <<Paste>>, 58 * <<PasteSelection>>, 59 * <<PrevWindow>>, 60 * <<Redo>>, 61 * <<Selection>>, 62 * <<Undo>>, 63 * <Alt-Key>, 64 * <B1-Enter>, 65 * <B1-Leave>, 66 * <B1-Motion>, 67 * <B2-Motion>, 68 * <Button-1>, 69 * <Button-2>, 70 * <Button-4>, 71 * <Button-5>, 72 * <ButtonRelease-1>, 73 * <Control-Button-1>, 74 * <Control-Key-Down>, 75 * <Control-Key-End>, 76 * <Control-Key-Home>, 77 * <Control-Key-Left>, 78 * <Control-Key-Next>, 79 * <Control-Key-Prior>, 80 * <Control-Key-Right>, 81 * <Control-Key-Tab>, 82 * <Control-Key-Up>, 83 * <Control-Key-a>, 84 * <Control-Key-b>, 85 * <Control-Key-backslash>, 86 * <Control-Key-d>, 87 * <Control-Key-e>, 88 * <Control-Key-f>, 89 * <Control-Key-h>, 90 * <Control-Key-i>, 91 * <Control-Key-k>, 92 * <Control-Key-n>, 93 * <Control-Key-o>, 94 * <Control-Key-p>, 95 * <Control-Key-slash>, 96 * <Control-Key-space>, 97 * <Control-Key-t>, 98 * <Control-Key>, 99 * <Control-Shift-Key-Down>, 100 * <Control-Shift-Key-End>, 101 * <Control-Shift-Key-Home>, 102 * <Control-Shift-Key-Left>, 103 * <Control-Shift-Key-Right>, 104 * <Control-Shift-Key-Tab>, 105 * <Control-Shift-Key-Up>, 106 * <Control-Shift-Key-space>, 107 * <Double-Button-1>, 108 * <Double-Shift-Button-1>, 109 * <Key-BackSpace>, 110 * <Key-Delete>, 111 * <Key-Down>, 112 * <Key-End>, 113 * <Key-Escape>, 114 * <Key-F10>, 115 * <Key-Home>, 116 * <Key-Insert>, 117 * <Key-KP_Enter>, 118 * <Key-Left>, 119 * <Key-Next>, 120 * <Key-Prior>, 121 * <Key-Return>, 122 * <Key-Right>, 123 * <Key-Select>, 124 * <Key-Tab>, 125 * <Key-Up>, 126 * <Key>, 127 * <Meta-Key-BackSpace>, 128 * <Meta-Key-Delete>, 129 * <Meta-Key-b>, 130 * <Meta-Key-d>, 131 * <Meta-Key-f>, 132 * <Meta-Key-greater>, 133 * <Meta-Key-less>, 134 * <Meta-Key>, 135 * <MouseWheel>, 136 * <Shift-Button-1>, 137 * <Shift-Key-Down>, 138 * <Shift-Key-End>, 139 * <Shift-Key-Home>, 140 * <Shift-Key-Left>, 141 * <Shift-Key-Next>, 142 * <Shift-Key-Prior>, 143 * <Shift-Key-Right>, 144 * <Shift-Key-Select>, 145 * <Shift-Key-Tab>, 146 * <Shift-Key-Up>, 147 * <Triple-Button-1>, 148 * <Triple-Shift-Button-1>, 149 * ) 150 * 151 * See_Also: 152 * $(LINK2 ./widget.html, tkd.widget.widget) 153 */ 154 class Text : Widget, IXScrollable!(Text), IYScrollable!(Text) 155 { 156 /** 157 * Construct the widget. 158 * 159 * Params: 160 * parent = The parent of this widget. 161 * 162 * See_Also: 163 * $(LINK2 ../element/uielement.html, tkd.element.UiElement) $(BR) 164 */ 165 public this(UiElement parent = null) 166 { 167 super(parent); 168 this._elementId = "text"; 169 170 this._tk.eval("text %s -highlightthickness 0", this.id); 171 172 this.setUndoSupport(true); 173 this.setUndoLevels(25); 174 this.setWrapMode(TextWrapMode.word); 175 } 176 177 /** 178 * Set the amount of padding in the text widget. 179 * 180 * Params: 181 * padding = The amount of padding in the text widget. 182 * 183 * Returns: 184 * This widget to aid method chaining. 185 */ 186 public auto setPadding(this T)(int padding) 187 { 188 this._tk.eval("%s configure -padx %s -pady %s", this.id, padding, padding); 189 190 return cast(T) this; 191 } 192 193 /** 194 * Set if the widget is readonly or not. 195 * 196 * Params: 197 * readOnly = Flag to toggle readonly state. 198 * 199 * Returns: 200 * This widget to aid method chaining. 201 */ 202 public auto setReadOnly(this T)(bool readOnly = true) 203 { 204 if(readOnly) 205 { 206 this._tk.eval("%s configure -state disabled", this.id); 207 } 208 else 209 { 210 this._tk.eval("%s configure -state normal", this.id); 211 } 212 213 return cast(T) this; 214 } 215 216 /** 217 * Enable or disable undo support. 218 * 219 * Params: 220 * enable = True to enable undo support, false to disable it. 221 * 222 * Returns: 223 * This widget to aid method chaining. 224 */ 225 public auto setUndoSupport(this T)(bool enable) 226 { 227 this._tk.eval("%s configure -undo %s", this.id, enable); 228 229 return cast(T) this; 230 } 231 232 /** 233 * Set the number of undo levels the widget will support. 234 * 235 * Params: 236 * undoLevels = The number of undo levels the widget will support. 237 * 238 * Returns: 239 * This widget to aid method chaining. 240 */ 241 public auto setUndoLevels(this T)(int undoLevels) 242 { 243 this._tk.eval("%s configure -maxundo %s", this.id, undoLevels); 244 245 return cast(T) this; 246 } 247 248 /** 249 * Set the wrap mode of the text. 250 * 251 * Params: 252 * mode = The mode to wrap the text with. 253 * 254 * Returns: 255 * This widget to aid method chaining. 256 * 257 * See_Also: 258 * $(LINK2 ./textwrapmode.html, tkd.widget.textwrapmode) 259 */ 260 public auto setWrapMode(this T)(string mode) 261 { 262 this._tk.eval("%s configure -wrap %s", this.id, mode); 263 264 return cast(T) this; 265 } 266 267 /** 268 * Appends text to the widget. 269 * 270 * Params: 271 * text = The text to append. 272 * 273 * Returns: 274 * This widget to aid method chaining. 275 */ 276 public auto appendText(this T)(string text) 277 { 278 // String concatenation is used to build the script here instead of 279 // using format specifiers to enable supporting input which includes 280 // Tcl/Tk reserved characters and elements that could be construed as 281 // format specifiers. 282 string script = std.conv.text(this.id, ` insert end "`, this._tk.escape(text), `"`); 283 this._tk.eval(script); 284 285 return cast(T) this; 286 } 287 288 /** 289 * Inserts text into the widget at a specified line and character index. 290 * 291 * Params: 292 * line = The line at which to insert the text. Indexes start at 1. 293 * character = The character at which to insert the text. Indexes start at 0. 294 * text = The text to insert. 295 * 296 * Returns: 297 * This widget to aid method chaining. 298 */ 299 public auto insertText(this T)(int line, int character, string text) 300 { 301 // String concatenation is used to build the script here instead of 302 // using format specifiers to enable supporting input which includes 303 // Tcl/Tk reserved characters and elements that could be construed as 304 // format specifiers. 305 string script = std.conv.text(this.id, ` insert `, line, `.`, character, ` "`, this._tk.escape(text), `"`); 306 this._tk.eval(script); 307 308 return cast(T) this; 309 } 310 311 /** 312 * Get the text from the widget. 313 * 314 * Returns: 315 * The text from the widget. 316 */ 317 public string getText(this T)() 318 { 319 this._tk.eval("%s get 0.0 end", this.id); 320 321 return this._tk.getResult!(string); 322 } 323 324 /** 325 * Delete text from the widget. 326 * 327 * Params: 328 * fromLine = The line from which to start deleting. Indexes start at 1. 329 * fromChar = The character from which to start deleting. Indexes start at 0. 330 * toLine = The line up to (but not including) which to delete. Indexes start at 1. 331 * toChar = The character up to (but not including) which to delete. Indexes start at 0. 332 * 333 * Returns: 334 * This widget to aid method chaining. 335 */ 336 public auto deleteText(this T)(int fromLine, int fromChar, int toLine, int toChar) 337 { 338 this._tk.eval("%s delete %s.%s %s.%s", this.id, fromLine, fromChar, toLine, toChar); 339 340 return cast(T) this; 341 } 342 343 /** 344 * Delete all content from the widget. 345 * 346 * Returns: 347 * This widget to aid method chaining. 348 */ 349 public auto clear(this T)() 350 { 351 this._tk.eval("%s delete 0.0 end", this.id); 352 353 return cast(T) this; 354 } 355 356 /** 357 * Embed a widget into the text. 358 * 359 * Params: 360 * line = The line at which to insert the text. Indexes start at 1. 361 * character = The character at which to insert the text. Indexes start at 0. 362 * widget = The widget to embed. 363 * padding = The amount of padding around the widget. 364 * 365 * Returns: 366 * This widget to aid method chaining. 367 */ 368 public auto embedWidget(this T)(int line, int character, Widget widget, int padding = 0) 369 { 370 this._tk.eval("%s window create %s.%s -window %s -align center -padx %s -pady %s", this.id, line, character, widget.id, padding, padding); 371 372 return cast(T) this; 373 } 374 375 /** 376 * Embed an image into the text. 377 * 378 * Params: 379 * line = The line at which to insert the text. Indexes start at 1. 380 * character = The character at which to insert the text. Indexes start at 0. 381 * image = The image to embed. 382 * padding = The amount of padding around the widget. 383 * 384 * Returns: 385 * This widget to aid method chaining. 386 */ 387 public auto embedImage(this T)(int line, int character, Image image, int padding = 0) 388 { 389 this._tk.eval("%s image create %s.%s -image %s -align center -padx %s -pady %s", this.id, line, character, image.id, padding, padding); 390 391 return cast(T) this; 392 } 393 394 /** 395 * Undo the last edit to the widget. This only applied to the widget if 396 * undo is enabled. 397 * 398 * Returns: 399 * This widget to aid method chaining. 400 */ 401 public auto undo(this T)() 402 { 403 this._tk.eval("%s edit undo", this.id); 404 405 return cast(T) this; 406 } 407 408 /** 409 * Redo the last edit to the widget. This only applied to the widget if 410 * undo is enabled. 411 * 412 * Returns: 413 * This widget to aid method chaining. 414 */ 415 public auto redo(this T)() 416 { 417 this._tk.eval("%s edit redo", this.id); 418 419 return cast(T) this; 420 } 421 422 /** 423 * Clear all undo's. This only applied to the widget if 424 * undo is enabled. 425 * 426 * Returns: 427 * This widget to aid method chaining. 428 */ 429 public auto resetUndo(this T)() 430 { 431 this._tk.eval("%s edit reset", this.id); 432 433 return cast(T) this; 434 } 435 436 /** 437 * See a particular text index. The text widget automatically scrolls to 438 * see the passed indexes. 439 * 440 * Params: 441 * line = The line to see. Indexes start at 1. 442 * character = The character to see. Indexes start at 0. 443 * 444 * Returns: 445 * This widget to aid method chaining. 446 */ 447 public auto seeText(this T)(int line, int character = 0) 448 { 449 this._tk.eval("%s see %s.%s", this.id, line, character); 450 451 return cast(T) this; 452 } 453 454 /** 455 * Cut the selected text to the clipboard. 456 * 457 * Returns: 458 * This widget to aid method chaining. 459 */ 460 public auto cutText(this T)() 461 { 462 this._tk.eval("tk_textCut %s", this.id); 463 464 return cast(T) this; 465 } 466 467 /** 468 * Copy the selected text to the clipboard. 469 * 470 * Returns: 471 * This widget to aid method chaining. 472 */ 473 public auto copyText(this T)() 474 { 475 this._tk.eval("tk_textCopy %s", this.id); 476 477 return cast(T) this; 478 } 479 480 /** 481 * Paste the selected text from the clipboard at the cursor position. 482 * 483 * Returns: 484 * This widget to aid method chaining. 485 */ 486 public auto pasteText(this T)() 487 { 488 this._tk.eval("tk_textPaste %s", this.id); 489 490 return cast(T) this; 491 } 492 493 /** 494 * Mixin common commands. 495 */ 496 mixin Border; 497 mixin Height; 498 mixin Relief; 499 mixin Width; 500 mixin XScrollCommand!(Text); 501 mixin XView; 502 mixin YScrollCommand!(Text); 503 mixin YView; 504 }