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