1 /**
2  * Widget module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.widget.canvas;
8 
9 /**
10  * Imports.
11  */
12 import std.algorithm;
13 import std.array;
14 import std.conv;
15 import std..string;
16 import std.uni;
17 import tkd.element.color;
18 import tkd.element.element;
19 import tkd.element.uielement;
20 import tkd.image.image;
21 import tkd.widget.anchorposition;
22 import tkd.widget.common.border;
23 import tkd.widget.common.canvas.anchor;
24 import tkd.widget.common.canvas.arcspecific;
25 import tkd.widget.common.canvas.bind;
26 import tkd.widget.common.canvas.fillcolor;
27 import tkd.widget.common.canvas.imagespecific;
28 import tkd.widget.common.canvas.linespecific;
29 import tkd.widget.common.canvas.outlinecolor;
30 import tkd.widget.common.canvas.outlinedash;
31 import tkd.widget.common.canvas.outlinewidth;
32 import tkd.widget.common.canvas.state;
33 import tkd.widget.common.canvas.textspecific;
34 import tkd.widget.common.canvas.vertex;
35 import tkd.widget.common.canvas.widgetspecific;
36 import tkd.widget.common.height;
37 import tkd.widget.common.relief;
38 import tkd.widget.common.width;
39 import tkd.widget.common.xscrollcommand;
40 import tkd.widget.common.xview;
41 import tkd.widget.common.yscrollcommand;
42 import tkd.widget.common.yview;
43 import tkd.widget.reliefstyle;
44 import tkd.widget.widget;
45 
46 /**
47  * Canvas widgets implement structured graphics. A canvas displays any number 
48  * of items, which may be things like rectangles, circles, lines, and text.  
49  * Items may be manipulated (e.g. moved or re-colored) and commands may be 
50  * associated with items in much the same way that the bind command allows 
51  * commands to be bound to widgets.
52  *
53  * Example:
54  * ---
55  * auto canvas = new Canvas(Color.white)
56  * 	.setWidth(350)
57  * 	.setHeight(250)
58  * 	.addItem(new CanvasRectangle([10, 10, 200, 100]))
59  * 	.bind("<ButtonPress-1>", delegate(CommandArgs args){ ... })
60  * 	.pack();
61  * ---
62  *
63  * Common_Commands:
64  *     These are injected common commands that can also be used with this widget.
65  *     $(P
66  *         $(LINK2 ./common/border.html, Border) $(BR)
67  *         $(LINK2 ./common/height.html, Height) $(BR)
68  *         $(LINK2 ./common/relief.html, Relief) $(BR)
69  *         $(LINK2 ./common/width.html, Width) $(BR)
70  *         $(LINK2 ./common/xscrollcommand.html, XScrollCommand) $(BR)
71  *         $(LINK2 ./common/xview.html, XView) $(BR)
72  *         $(LINK2 ./common/yscrollcommand.html, YScrollCommand) $(BR)
73  *         $(LINK2 ./common/yview.html, YView) $(BR)
74  *     )
75  *
76  * Additional_Events:
77  *     Additional events that can also be bound to using the $(LINK2 ../element/uielement.html#UiElement.bind, bind) method.
78  *     $(P
79  *         &lt;&lt;PrevWindow&gt;&gt;,
80  *         &lt;Alt-Key&gt;,
81  *         &lt;Key-F10&gt;,
82  *         &lt;Key-Tab&gt;,
83  *     )
84  *
85  * See_Also:
86  *     $(LINK2 ./widget.html, tkd.widget.widget)
87  */
88 class Canvas : Widget, IXScrollable!(Canvas), IYScrollable!(Canvas)
89 {
90 	/**
91 	 * Construct the widget.
92 	 *
93 	 * Params:
94 	 *     parent = The parent of this widget.
95 	 *     backgroundColor = The background color.
96 	 *
97 	 * See_Also:
98 	 *     $(LINK2 ../element/uielement.html, tkd.element.UiElement) $(BR)
99 	 */
100 	public this(UiElement parent, string backgroundColor = Color.default_)
101 	{
102 		super(parent);
103 		this._elementId = "canvas";
104 
105 		this._tk.eval("canvas %s", this.id);
106 
107 		this.setBorderWidth(1);
108 		this.setRelief(ReliefStyle.sunken);
109 		this.setBackgroundColor(backgroundColor);
110 	}
111 
112 	/**
113 	 * Construct the widget.
114 	 *
115 	 * Params:
116 	 *     backgroundColor = The background color.
117 	 *
118 	 * See_Also:
119 	 *     $(LINK2 ../element/uielement.html, tkd.element.UiElement) $(BR)
120 	 */
121 	public this(string backgroundColor = Color.default_)
122 	{
123 		this(null, backgroundColor);
124 	}
125 
126 	/**
127 	 * Set the background color.
128 	 * Use colors from the preset color $(LINK2 ../element/color.html, list) or a web style hex color.
129 	 *
130 	 * Params:
131 	 *     color = The background color.
132 	 *
133 	 * Returns:
134 	 *     This widget to aid method chaining.
135 	 *
136 	 * See_Also:
137 	 *     $(LINK2 ../element/color.html, tkd.widget.color) $(BR)
138 	 */
139 	public auto setBackgroundColor(this T)(string color)
140 	{
141 		if (color.length)
142 		{
143 			this._tk.eval("%s configure -background {%s}", this.id, color);
144 		}
145 
146 		return cast(T) this;
147 	}
148 
149 	/**
150 	 * Specifies a floating-point value indicating how close the mouse cursor 
151 	 * must be to an item before it is considered to be 'inside' the item and 
152 	 * able to select it.  Defaults to 1.0.
153 	 *
154 	 * Params:
155 	 *     tolerance = The tolerance of the selection.
156 	 *
157 	 * Returns:
158 	 *     This widget to aid method chaining.
159 	 */
160 	public auto setSelectionTolerance(this T)(double tolerance)
161 	{
162 		this._tk.eval("%s configure -closeenough %s", this.id, tolerance);
163 
164 		return cast(T) this;
165 	}
166 
167 	/**
168 	 * Set the scroll region of the canvas. This region can be scrolled using 
169 	 * scrollbars if it's bigger than the canvas widget itself.
170 	 *
171 	 * Params:
172 	 *     left = The left hand side of the widget.
173 	 *     top = The top side of the widget.
174 	 *     right = The right hand side of the widget.
175 	 *     bottom = The bottom side of the widget.
176 	 *
177 	 * Returns:
178 	 *     This widget to aid method chaining.
179 	 */
180 	public auto setScrollRegion(this T)(double left, double top, double right, double bottom)
181 	{
182 		this._tk.eval("%s configure -scrollregion [list %s %s %s %s]", this.id, left, top, right, bottom);
183 
184 		return cast(T) this;
185 	}
186 
187 	/**
188 	 * Set the scroll increment i.e. how many pixels are scrolled per each 
189 	 * click on a scrollbar.
190 	 *
191 	 * Params:
192 	 *     increment = The increment to scroll by.
193 	 *
194 	 * Returns:
195 	 *     This widget to aid method chaining.
196 	 */
197 	public auto setScrollIncrement(this T)(int increment)
198 	{
199 		this._tk.eval("%s configure -xscrollincrement %s -yscrollincrement %s", this.id, increment, increment);
200 
201 		return cast(T) this;
202 	}
203 
204 	/**
205 	 * Get the horizontal position on the canvas that relates to a particular 
206 	 * horizontal position on screen.
207 	 *
208 	 * Params:
209 	 *     screenXPos = The horizontal screen position to transpose.
210 	 *     gridSpacing = The grid spacing to round it to.
211 	 *
212 	 * Returns:
213 	 *     The horizontal canvas position.
214 	 */
215 	public int getXPosFromScreen(int screenXPos, int gridSpacing = 1)
216 	{
217 		this._tk.eval("%s canvasx %s %s", this.id, screenXPos, gridSpacing);
218 
219 		return this._tk.getResult!(string).chomp(".0").to!(int) - this.getXPos();
220 	}
221 
222 	/**
223 	 * Get the vertical position on the canvas that relates to a particular 
224 	 * vertical position on screen.
225 	 *
226 	 * Params:
227 	 *     screenYPos = The vertical screen position to transpose.
228 	 *     gridSpacing = The grid spacing to round it to.
229 	 *
230 	 * Returns:
231 	 *     The vertical canvas position.
232 	 */
233 	public int getYPosFromScreen(int screenYPos, int gridSpacing = 1)
234 	{
235 		this._tk.eval("%s canvasy %s %s", this.id, screenYPos, gridSpacing);
236 
237 		return this._tk.getResult!(string).chomp(".0").to!(int) - this.getYPos();
238 	}
239 
240 	/**
241 	 * Tag an item nearest to coordinates. If more than one item is at the same 
242 	 * closest distance (e.g. two items overlap the point), then the top-most 
243 	 * of these items (the last one in the display list) is used. If radius is 
244 	 * specified, then it must be a non-negative value. Any item closer than 
245 	 * halo to the point is considered to overlap it.
246 	 *
247 	 * Params:
248 	 *    tag = The tag to add.
249 	 *    xPos = The horizontal position.
250 	 *    yPos = The vertical position.
251 	 *    radius = The radius around the point.
252 	 *
253 	 * Returns:
254 	 *     This widget to aid method chaining.
255 	 */
256 	public auto tagItemNear(this T)(string tag, int xPos, int yPos, uint radius = 0)
257 	{
258 		if (tag.length)
259 		{
260 			this._tk.eval("%s addtag %s closest %s %s %s", this.id, tag, xPos, yPos, radius);
261 		}
262 
263 		return cast(T) this;
264 	}
265 
266 	/**
267 	 * Tag items within a selection region.
268 	 *
269 	 * Params:
270 	 *    tag = The tag to add.
271 	 *    x1 = The left edge of the selection region.
272 	 *    y1 = The top edge of the selection region.
273 	 *    x2 = The right edge of the selection region.
274 	 *    y2 = The bottom edge of the selection region.
275 	 *    enclosedFully = Specifies if the items have to be enclosed fully or not.
276 	 *
277 	 * Returns:
278 	 *     This widget to aid method chaining.
279 	 */
280 	public auto tagItemIn(this T)(string tag, int x1, int y1, int x2, int y2, bool enclosedFully = false)
281 	{
282 		assert(x1 <= x2, "x1 must not be greater than x2.");
283 		assert(y1 <= y2, "y1 must not be greater than y2.");
284 
285 		if (tag.length)
286 		{
287 			if (enclosedFully)
288 			{
289 				this._tk.eval("%s addtag %s enclosed %s %s %s %s", this.id, tag, x1, y1, x2, y2);
290 			}
291 			else
292 			{
293 				this._tk.eval("%s addtag %s overlapping %s %s %s %s", this.id, tag, x1, y1, x2, y2);
294 			}
295 		}
296 
297 		return cast(T) this;
298 	}
299 
300 	/**
301 	 * Tag items that are already tagged with another tag.
302 	 *
303 	 * Params:
304 	 *    tag = The tag to add.
305 	 *    searchTag = The tag to select items to tag.
306 	 *
307 	 * Returns:
308 	 *     This widget to aid method chaining.
309 	 */
310 	public auto tagItemWithTag(this T)(string tag, string searchTag)
311 	{
312 		if (tag.length && searchTag.length)
313 		{
314 			this._tk.eval("%s addtag %s withtag %s", this.id, tag, searchTag);
315 		}
316 
317 		return cast(T) this;
318 	}
319 
320 	/**
321 	 * Get an item id nearest to coordinates. If more than one item is at the 
322 	 * same closest distance (e.g. two items overlap the point), then the 
323 	 * top-most of these items (the last one in the display list) is used. If 
324 	 * radius is specified, then it must be a non-negative value. Any item 
325 	 * closer than halo to the point is considered to overlap it.
326 	 *
327 	 * Params:
328 	 *    xPos = The horizontal position.
329 	 *    yPos = The vertical position.
330 	 *    radius = The radius around the point.
331 	 *
332 	 * Returns:
333 	 *     The item found.
334 	 */
335 	public int getItemIdNear(int xPos, int yPos, uint radius = 0)
336 	{
337 		this._tk.eval("%s find closest %s %s %s", this.id, xPos, yPos, radius);
338 
339 		return this._tk.getResult!(int);
340 	}
341 
342 	/**
343 	 * Get items within a selection region.
344 	 *
345 	 * Params:
346 	 *    x1 = The left edge of the selection region.
347 	 *    y1 = The top edge of the selection region.
348 	 *    x2 = The right edge of the selection region.
349 	 *    y2 = The bottom edge of the selection region.
350 	 *    enclosedFully = Specifies if the items have to be enclosed fully or not.
351 	 *
352 	 * Returns:
353 	 *     An array of found items.
354 	 */
355 	public int[] getItemIdsIn(int x1, int y1, int x2, int y2, bool enclosedFully = false)
356 	{
357 		assert(x1 <= x2, "x1 must not be greater than x2.");
358 		assert(y1 <= y2, "y1 must not be greater than y2.");
359 
360 		if (enclosedFully)
361 		{
362 			this._tk.eval("%s find enclosed %s %s %s %s", this.id, x1, y1, x2, y2);
363 		}
364 		else
365 		{
366 			this._tk.eval("%s find overlapping %s %s %s %s", this.id, x1, y1, x2, y2);
367 		}
368 
369 		return this._tk.getResult!(string).split().map!(to!(int)).array;
370 	}
371 
372 	/**
373 	 * Add an item to the canvas.
374 	 *
375 	 * Params:
376 	 *     item = The item to add.
377 	 *
378 	 * Returns:
379 	 *     This widget to aid method chaining.
380 	 */
381 	public auto addItem(this T)(CanvasItem item)
382 	{
383 		this._tk.eval("%s create %s [list %s]", this.id, item._type, item._coords.map!(to!(string)).join(" "));
384 
385 		item.overrideGeneratedId(this._tk.getResult!(string));
386 		item.init(this);
387 
388 		return cast(T) this;
389 	}
390 
391 	/**
392 	 * Add a tag configuration to the canvas. These can apply options to a tag 
393 	 * which can then be applied to any item.
394 	 *
395 	 * Params:
396 	 *     tagConfig = The configuration to add.
397 	 *
398 	 * Returns:
399 	 *     This widget to aid method chaining.
400 	 */
401 	public auto addTagConfig(this T)(CanvasTagConfig tagConfig)
402 	{
403 		tagConfig.init(this);
404 
405 		return cast(T) this;
406 	}
407 
408 	/**
409 	 * This command is used to implement scanning on canvases. Records x and y 
410 	 * positions and the canvas's current view. This is used in conjunction 
411 	 * with later scanDragTo commands.
412 	 *
413 	 * Params:
414 	 *     xPos = The marked horizontal starting point of a scan.
415 	 *     yPos = The marked vertical starting point of a scan.
416 	 *
417 	 * Returns:
418 	 *     This widget to aid method chaining.
419 	 *
420 	 * See_Also:
421 	 *     $(LINK2 ./canvas.html#Canvas.scanDragTo, tkd.widget.canvas.Canvas.scanDragTo)
422 	 */
423 	public auto setScanMark(this T)(double xPos, double yPos)
424 	{
425 		this._tk.eval("%s scan mark %s %s", this.id, xPos, yPos);
426 
427 		return cast(T) this;
428 	}
429 
430 	/**
431 	 * This command is used to implement scanning on canvases. This command 
432 	 * computes the difference between its xPos and yPos arguments (which are 
433 	 * typically mouse coordinates) and the xPos and yPos arguments to the last 
434 	 * setScanMark command for the widget. It then adjusts the view by gain 
435 	 * times the difference in coordinates, where gain defaults to 1. This 
436 	 * command is typically associated with mouse motion events in the widget, 
437 	 * to produce the effect of dragging the canvas at high speed through its 
438 	 * window.
439 	 *
440 	 * Params:
441 	 *     xPos = The marked horizontal starting point of a scan.
442 	 *     yPos = The marked vertical starting point of a scan.
443 	 *     gain = The adjustment in the drag amount.
444 	 *
445 	 * Returns:
446 	 *     This widget to aid method chaining.
447 	 *
448 	 * See_Also:
449 	 *     $(LINK2 ./canvas.html#Canvas.setScanMark, tkd.widget.canvas.Canvas.setScanMark)
450 	 */
451 	public auto scanDragTo(this T)(double xPos, double yPos, int gain = 1)
452 	{
453 		this._tk.eval("%s scan dragto %s %s %s", this.id, xPos, yPos, gain);
454 
455 		return cast(T) this;
456 	}
457 
458 	/**
459 	 * Mixin common commands.
460 	 */
461 	mixin Border;
462 	mixin Height;
463 	mixin Relief;
464 	mixin Width;
465 	mixin XScrollCommand!(Canvas);
466 	mixin XView;
467 	mixin YScrollCommand!(Canvas);
468 	mixin YView;
469 }
470 
471 /**
472  * Class representing a tag configuration. Tags can be applied to numerous 
473  * items on the canvas but keep in mind the tag options set in the 
474  * configuration must be compatible for all items the tag is assigned to or an 
475  * error will occur. Tags must be applied to items before they can be 
476  * configured.
477  *
478  * Common_Commands:
479  *     These are injected common commands that can also be used with this widget.
480  *     $(P
481  *         $(LINK2 ./common/canvas/anchor.html, Anchor) $(BR)
482  *         $(LINK2 ./common/canvas/arcspecific.html, ArcSpecific) $(BR)
483  *         $(LINK2 ./common/canvas/bind.html, Bind) $(BR)
484  *         $(LINK2 ./common/canvas/fillcolor.html, FillColor) $(BR)
485  *         $(LINK2 ./common/canvas/imagespecific.html, ImageSpecific) $(BR)
486  *         $(LINK2 ./common/canvas/linespecific.html, LineSpecific) $(BR)
487  *         $(LINK2 ./common/canvas/outlinecolor.html, OutlineColor) $(BR)
488  *         $(LINK2 ./common/canvas/outlinedash.html, OutlineDash) $(BR)
489  *         $(LINK2 ./common/canvas/outlinewidth.html, OutlineWidth) $(BR)
490  *         $(LINK2 ./common/canvas/state.html, State) $(BR)
491  *         $(LINK2 ./common/canvas/textspecific.html, TextSpecific) $(BR)
492  *         $(LINK2 ./common/canvas/vertex.html, Vertex) $(BR)
493  *         $(LINK2 ./common/canvas/widgetspecific.html, WidgetSpecific) $(BR)
494  *     )
495  *
496  * See_Also:
497  *     $(LINK2 ../element/element.html, tkd.element.element)
498  */
499 class CanvasTagConfig : Element
500 {
501 	/**
502 	 * Constructor.
503 	 *
504 	 * Params:
505 	 *     tagName = The name of the tag to configure.
506 	 */
507 	this(string tagName)
508 	{
509 		this.overrideGeneratedId(tagName);
510 	}
511 
512 	/*
513 	 * Initialise the item.
514 	 *
515 	 * Params:
516 	 *     parent = The parent canvas to initialise against.
517 	 */
518 	protected void init(Canvas parent)
519 	{
520 		this._parent = parent;
521 
522 		foreach (binding, callback; this._bindings)
523 		{
524 			this.bind(binding, callback);
525 		}
526 
527 		this.setActiveFillColor(this._activeFillColor);
528 		this.setActiveImage(this._activeImage);
529 		this.setActiveOutlineColor(this._activeOutlineColor);
530 		this.setActiveOutlineDash(this._activeOutlineDash);
531 		this.setActiveOutlineWidth(this._activeOutlineWidth);
532 		this.setAlignment(this._alignment);
533 		this.setAnchor(this._anchor);
534 		this.setAngle(this._angle);
535 		this.setArrowPosition(this._arrowPosition);
536 		this.setArrowShape(this._arrowShape);
537 		this.setCapStyle(this._capStyle);
538 		this.setDisabledFillColor(this._disabledFillColor);
539 		this.setDisabledImage(this._disabledImage);
540 		this.setDisabledOutlineColor(this._disabledOutlineColor);
541 		this.setDisabledOutlineDash(this._disabledOutlineDash);
542 		this.setDisabledOutlineWidth(this._disabledOutlineWidth);
543 		this.setExtent(this._extent);
544 		this.setFillColor(this._fillColor);
545 		this.setFont(this._font);
546 		this.setHeight(this._height);
547 		this.setImage(this._image);
548 		this.setJoinStyle(this._joinStyle);
549 		this.setMaxLineLength(this._maxLineLength);
550 		this.setOutlineColor(this._outlineColor);
551 		this.setOutlineDash(this._outlineDash);
552 		this.setOutlineDashOffset(this._outlineDashOffset);
553 		this.setOutlineWidth(this._outlineWidth);
554 		this.setSmoothMethod(this._smoothMethod);
555 		this.setSmoothSplineSteps(this._splineSteps);
556 		this.setStartAngle(this._startAngle);
557 		this.setState(this._state);
558 		this.setStyle(this._style);
559 		this.setText(this._text);
560 		this.setWidget(this._widget);
561 		this.setWidth(this._width);
562 	}
563 
564 	/**
565 	 * Mixin common commands.
566 	 */
567 	mixin Anchor;
568 	mixin ArcSpecific;
569 	mixin Bind;
570 	mixin FillColor;
571 	mixin ImageSpecific;
572 	mixin LineSpecific;
573 	mixin OutlineColor;
574 	mixin OutlineDash;
575 	mixin OutlineWidth;
576 	mixin State;
577 	mixin TextSpecific;
578 	mixin Vertex;
579 	mixin WidgetSpecific;
580 }
581 
582 /**
583  * Abstract base class of all canvas items.
584  *
585  * Common_Commands:
586  *     These are injected common commands that can also be used with this widget.
587  *     $(P
588  *         $(LINK2 ./common/canvas/bind.html, Bind) $(BR)
589  *         $(LINK2 ./common/canvas/state.html, State) $(BR)
590  *     )
591  *
592  * See_Also:
593  *     $(LINK2 ../element/element.html, tkd.element.element)
594  */
595 protected abstract class CanvasItem : Element
596 {
597 	/**
598 	 * The type of the item.
599 	 */
600 	private string _type;
601 
602 	/**
603 	 * The coordinates where to draw the item.
604 	 */
605 	private double[] _coords;
606 
607 	/**
608 	 * The tags associated with this item.
609 	 */
610 	private string[] _tags;
611 
612 	/**
613 	 * Get the type of canvas item.
614 	 *
615 	 * Returns:
616 	 *     The type of canvas item.
617 	 */
618 	public @property string type()
619 	{
620 		return this._type;
621 	}
622 
623 	/*
624 	 * Initialise the item.
625 	 *
626 	 * Params:
627 	 *     parent = The parent canvas to initialise against.
628 	 */
629 	protected void init(Canvas parent)
630 	{
631 		this._parent = parent;
632 
633 		foreach (binding, callback; this._bindings)
634 		{
635 			this.bind(binding, callback);
636 		}
637 
638 		this.setState(this._state);
639 
640 		this.setTags(this._tags);
641 	}
642 
643 	/**
644 	 * Get the coords of this item.
645 	 *
646 	 * Returns:
647 	 *     An array of coords of this item.
648 	 */
649 	public double[] getCoords()
650 	{
651 		if (this._parent)
652 		{
653 			this._tk.eval("%s coords %s", this._parent.id, this.id);
654 			this._coords = this._tk.getResult!(string).split().map!(to!(double)).array;
655 		}
656 
657 		return this._coords;
658 	}
659 
660 	/**
661 	 * Set the coordinates used to draw this item.
662 	 *
663 	 * Params:
664 	 *    coords = The coords used for this item.
665 	 *
666 	 * Returns:
667 	 *     This item to aid method chaining.
668 	 */
669 	public auto setCoords(this T)(double[] coords)
670 	{
671 		assert(coords.length >= 2, "Not enough coordinates specified.");
672 
673 		this._coords = coords;
674 
675 		if (this._parent)
676 		{
677 			this._tk.eval("%s coords %s [list %s]", this._parent.id, this.id, this._coords.map!(to!(string)).join(" "));
678 		}
679 
680 		return cast(T) this;
681 	}
682 
683 	/**
684 	 * Get the tags associated with this item.
685 	 *
686 	 * Returns:
687 	 *     An array of tags associated with this item.
688 	 */
689 	public string[] getTags()
690 	{
691 		if (this._parent)
692 		{
693 			this._tk.eval("%s gettags %s", this._parent.id, this.id);
694 			this._tags = this._tk.getResult!(string).split();
695 		}
696 
697 		return this._tags;
698 	}
699 
700 	/**
701 	 * Set tags associated with this item.
702 	 *
703 	 * Params:
704 	 *    tags = The tags to associated with this item.
705 	 *
706 	 * Returns:
707 	 *     This item to aid method chaining.
708 	 */
709 	public auto setTags(this T)(string[] tags)
710 	{
711 		foreach (tag; tags)
712 		{
713 			assert(!tag.all!(isNumber), "Tags must not be entirely composed of numbers.");
714 		}
715 
716 		this._tags = tags;
717 
718 		if (this._parent && this._tags.length)
719 		{
720 			this._tk.eval("%s itemconfigure %s -tags {%s}", this._parent.id, this.id, this._tags.join(" "));
721 		}
722 
723 		return cast(T) this;
724 	}
725 
726 	/**
727 	 * Add a specific tag to this item.
728 	 *
729 	 * Params:
730 	 *    tag = The tags to add.
731 	 *
732 	 * Returns:
733 	 *     This item to aid method chaining.
734 	 */
735 	public auto addTag(this T)(string tag)
736 	{
737 		assert(!tag.all!(isNumber), "Tags must not be entirely composed of numbers.");
738 
739 		this._tags = (this._tags ~= tag).uniq().array();
740 
741 		if (this._parent && tag.length)
742 		{
743 			this._tk.eval("%s addtag {%s} withtag %s", this._parent.id, tag, this.id);
744 		}
745 
746 		return cast(T) this;
747 	}
748 
749 	/**
750 	 * Delete a specific tag associated to this item.
751 	 *
752 	 * Params:
753 	 *    tag = The tags to delete.
754 	 *
755 	 * Returns:
756 	 *     This item to aid method chaining.
757 	 */
758 	public auto deleteTag(this T)(string tag)
759 	{
760 		if (this._tags.canFind(tag))
761 		{
762 			this._tags = std.algorithm.remove(this._tags, this._tags.countUntil(tag));
763 		}
764 
765 		if (this._parent && tag.length)
766 		{
767 			this._tk.eval("%s dtag %s {%s}", this._parent.id, this.id, tag);
768 		}
769 
770 		return cast(T) this;
771 	}
772 
773 	/**
774 	 * Delete all tags associated to this item.
775 	 *
776 	 * Returns:
777 	 *     This item to aid method chaining.
778 	 */
779 	public auto clearTags(this T)()
780 	{
781 		this._tags = [];
782 
783 		if (this._parent)
784 		{
785 			this._tk.eval("%s itemconfigure %s -tags {}", this._parent.id, this.id);
786 		}
787 
788 		return cast(T) this;
789 	}
790 
791 	/**
792 	 * Destroy this item and remove it from the canvas.
793 	 *
794 	 * Caveats:
795 	 *     Once an item is destroyed it can no longer be referenced in your 
796 	 *     code or a segmentation fault will occur and potentially crash your 
797 	 *     program.
798 	 */
799 	public void destroy()
800 	{
801 		if (this._parent)
802 		{
803 			this._tk.eval("%s delete %s", this._parent.id, this.id);
804 		}
805 
806 		super.destroy();
807 	}
808 
809 	/**
810 	 * Set the keyboard focus to this item in the canvas.
811 	 *
812 	 * Returns:
813 	 *     This widget to aid method chaining.
814 	 */
815 	public auto focus(this T)()
816 	{
817 		if (this._parent)
818 		{
819 			this._tk.eval("%s focus %s", this._parent.id, this.id);
820 		}
821 
822 		return cast(T) this;
823 	}
824 
825 	/**
826 	 * Lower an item in the drawing order.
827 	 *
828 	 * Returns:
829 	 *     This widget to aid method chaining.
830 	 */
831 	public auto lower(this T)()
832 	{
833 		if (this._parent)
834 		{
835 			this._tk.eval("%s lower %s", this._parent.id, this.id);
836 		}
837 
838 		return cast(T) this;
839 	}
840 
841 	/**
842 	 * Raise an item in the drawing order.
843 	 *
844 	 * Returns:
845 	 *     This widget to aid method chaining.
846 	 */
847 	public auto raise(this T)()
848 	{
849 		if (this._parent)
850 		{
851 			this._tk.eval("%s raise %s", this._parent.id, this.id);
852 		}
853 
854 		return cast(T) this;
855 	}
856 
857 	/**
858 	 * Move an item on the canvas by an amount.
859 	 *
860 	 * Params:
861 	 *     xAmount = The amount to move the item horizontally.
862 	 *     yAmount = The amount to move the item vertically.
863 	 *
864 	 * Returns:
865 	 *     This widget to aid method chaining.
866 	 */
867 	public auto moveBy(this T)(int xAmount, int yAmount)
868 	{
869 		if (this._parent)
870 		{
871 			this._tk.eval("%s move %s %s %s", this._parent.id, this.id, xAmount, yAmount);
872 		}
873 
874 		return cast(T) this;
875 	}
876 
877 	/**
878 	 * Move an item on the canvas to a position.
879 	 *
880 	 * Params:
881 	 *     xPos = The new horizontal position.
882 	 *     yPos = The new vertical position.
883 	 *
884 	 * Returns:
885 	 *     This widget to aid method chaining.
886 	 */
887 	public auto moveTo(this T)(int xPos, int yPos)
888 	{
889 		if (this._parent)
890 		{
891 			this._tk.eval("%s moveto %s %s %s", this._parent.id, this.id, xPos, yPos);
892 		}
893 
894 		return cast(T) this;
895 	}
896 
897 	/**
898 	 * Scale an item on the canvas. Note that some items have only a single 
899 	 * pair of coordinates (e.g., text, images and widgets) and so scaling of 
900 	 * them by this command can only move them around.
901 	 *
902 	 * Params:
903 	 *     xOrigin = The horizontal origin from which to perform the scale.
904 	 *     yOrigin = The vertical origin from which to perform the scale.
905 	 *     xPercent = The amount to scale horizontally.
906 	 *     yPercent = The amount to scale vertically.
907 	 *
908 	 * Returns:
909 	 *     This widget to aid method chaining.
910 	 */
911 	public auto scale(this T)(double xOrigin, double yOrigin, double xPercent, double yPercent)
912 	{
913 		if (this._parent)
914 		{
915 			this._tk.eval("%s scale %s %s %s %s %s", this._parent.id, this.id, xOrigin, yOrigin, xPercent / 100, yPercent / 100);
916 		}
917 
918 		return cast(T) this;
919 	}
920 
921 	/**
922 	 * Mixin common commands.
923 	 */
924 	mixin Bind;
925 	mixin State;
926 }
927 
928 /**
929  * A canvas arc item.
930  *
931  * Common_Commands:
932  *     These are injected common commands that can also be used with this canvas item.
933  *     $(P
934  *         $(LINK2 ./common/canvas/arcspecific.html, ArcSpecific) $(BR)
935  *         $(LINK2 ./common/canvas/fillcolor.html, FillColor) $(BR)
936  *         $(LINK2 ./common/canvas/outlinecolor.html, OutlineColor) $(BR)
937  *         $(LINK2 ./common/canvas/outlinedash.html, OutlineDash) $(BR)
938  *         $(LINK2 ./common/canvas/outlinewidth.html, OutlineWidth) $(BR)
939  *     )
940  *
941  * See_Also:
942  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
943  */
944 class CanvasArc : CanvasItem
945 {
946 	/**
947 	 * Create an arc.
948 	 * Use colors from the preset color $(LINK2 ../element/color.html, list) or a web style hex color.
949 	 *
950 	 * Params:
951 	 *     coords = The coordinates of the outer elipse.
952 	 *     style = The style of arc.
953 	 *     fillColor = The fill color.
954 	 *     outlineColor = The outline color.
955 	 *     outlineWidth = The outline width.
956 	 *
957 	 * See_Also:
958 	 *     $(LINK2 ../element/color.html, tkd.widget.color) $(BR)
959 	 *     $(LINK2 ./canvas.html#CanvasArcStyle, tkd.widget.canvas.CanvasArcStyle)
960 	 */
961 	public this(double[] coords, string style = CanvasArcStyle.pie, string fillColor = Color.default_, string outlineColor = Color.black, int outlineWidth = 1)
962 	{
963 		assert(coords.length == 4, "Four coordinates are needed to draw an arc.");
964 
965 		this._type         = "arc";
966 		this._coords       = coords;
967 		this._style        = style;
968 		this._fillColor    = fillColor;
969 		this._outlineColor = outlineColor;
970 		this._outlineWidth = outlineWidth;
971 	}
972 
973 	/*
974 	 * Initialise the item.
975 	 *
976 	 * Params:
977 	 *     parent = The parent canvas to initialise against.
978 	 */
979 	override protected void init(Canvas parent)
980 	{
981 		super.init(parent);
982 
983 		this.setActiveFillColor(this._activeFillColor);
984 		this.setActiveOutlineColor(this._activeOutlineColor);
985 		this.setActiveOutlineDash(this._activeOutlineDash);
986 		this.setActiveOutlineWidth(this._activeOutlineWidth);
987 		this.setDisabledFillColor(this._disabledFillColor);
988 		this.setDisabledOutlineColor(this._disabledOutlineColor);
989 		this.setDisabledOutlineDash(this._disabledOutlineDash);
990 		this.setDisabledOutlineWidth(this._disabledOutlineWidth);
991 		this.setExtent(this._extent);
992 		this.setFillColor(this._fillColor);
993 		this.setOutlineColor(this._outlineColor);
994 		this.setOutlineDash(this._outlineDash);
995 		this.setOutlineDashOffset(this._outlineDashOffset);
996 		this.setOutlineWidth(this._outlineWidth);
997 		this.setStartAngle(this._startAngle);
998 		this.setStyle(this._style);
999 	}
1000 
1001 	/**
1002 	 * Mixin common commands.
1003 	 */
1004 	mixin ArcSpecific;
1005 	mixin FillColor;
1006 	mixin OutlineColor;
1007 	mixin OutlineDash;
1008 	mixin OutlineWidth;
1009 }
1010 
1011 /**
1012  * Styles of arcs
1013  */
1014 enum CanvasArcStyle : string
1015 {
1016 	arc   = "arc",      /// Arc is drawn as an arc only.
1017 	chord = "chord",    /// Arc is drawn as a chord.
1018 	pie   = "pieslice", /// Arc is drawn as a pie chart.
1019 }
1020 
1021 /**
1022  * An canvas image item.
1023  *
1024  * Common_Commands:
1025  *     These are injected common commands that can also be used with this canvas item.
1026  *     $(P
1027  *         $(LINK2 ./common/canvas/anchor.html, Anchor) $(BR)
1028  *         $(LINK2 ./common/canvas/imagespecific.html, ImageSpecific) $(BR)
1029  *     )
1030  *
1031  * See_Also:
1032  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
1033  */
1034 class CanvasImage : CanvasItem
1035 {
1036 	/**
1037 	 * Create an image.
1038 	 *
1039 	 * Params:
1040 	 *     coords = The coordinates where to position the image.
1041 	 *     image = The image to draw.
1042 	 *     anchor = The anchor position of the image.
1043 	 *
1044 	 * See_Also:
1045 	 *     $(LINK2 ../image/gif.html, tkd.image.gif) $(BR)
1046 	 *     $(LINK2 ../image/image.html, tkd.image.image) $(BR)
1047 	 *     $(LINK2 ../image/png.html, tkd.image.png) $(BR)
1048 	 *     $(LINK2 ./anchorposition.html, tkd.widget.anchorposition) $(BR)
1049 	 */
1050 	public this(double[] coords, Image image, string anchor = AnchorPosition.northWest)
1051 	{
1052 		assert(coords.length == 2, "Two coordinates are needed to position an image.");
1053 
1054 		this._type   = "image";
1055 		this._coords = coords;
1056 		this._image  = image;
1057 		this._anchor = anchor;
1058 	}
1059 
1060 	/*
1061 	 * Initialise the item.
1062 	 *
1063 	 * Params:
1064 	 *     parent = The parent canvas to initialise against.
1065 	 */
1066 	override protected void init(Canvas parent)
1067 	{
1068 		super.init(parent);
1069 
1070 		this.setAnchor(this._anchor);
1071 		this.setImage(this._image);
1072 		this.setActiveImage(this._activeImage);
1073 		this.setDisabledImage(this._disabledImage);
1074 	}
1075 
1076 	/**
1077 	 * Mixin common commands.
1078 	 */
1079 	mixin Anchor;
1080 	mixin ImageSpecific;
1081 }
1082 
1083 /**
1084  * A canvas line item.
1085  *
1086  * Common_Commands:
1087  *     These are injected common commands that can also be used with this canvas item.
1088  *     $(P
1089  *         $(LINK2 ./common/canvas/fillcolor.html, FillColor) $(BR)
1090  *         $(LINK2 ./common/canvas/linespecific.html, LineSpecific) $(BR)
1091  *         $(LINK2 ./common/canvas/outlinedash.html, OutlineDash) $(BR)
1092  *         $(LINK2 ./common/canvas/outlinewidth.html, OutlineWidth) $(BR)
1093  *         $(LINK2 ./common/canvas/vertex.html, Vertex) $(BR)
1094  *     )
1095  *
1096  * See_Also:
1097  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
1098  */
1099 class CanvasLine : CanvasItem
1100 {
1101 	/**
1102 	 * Create a line from coordinates.
1103 	 * Use colors from the preset color $(LINK2 ../element/color.html, list) or a web style hex color.
1104 	 *
1105 	 * Params:
1106 	 *     coords = The coordinates where to draw the line.
1107 	 *     fillColor = The color of the line.
1108 	 *     outlineWidth = The outline width.
1109 	 *
1110 	 * See_Also:
1111 	 *     $(LINK2 ../element/color.html, tkd.widget.color) $(BR)
1112 	 */
1113 	public this(double[] coords, string fillColor = Color.black, int outlineWidth = 1)
1114 	{
1115 		assert(coords.length >= 4, "Four or more coordinates are needed to draw a line.");
1116 
1117 		this._type         = "line";
1118 		this._coords       = coords;
1119 		this._fillColor    = fillColor;
1120 		this._outlineWidth = outlineWidth;
1121 	}
1122 
1123 	/*
1124 	 * Initialise the item.
1125 	 *
1126 	 * Params:
1127 	 *     parent = The parent canvas to initialise against.
1128 	 */
1129 	override protected void init(Canvas parent)
1130 	{
1131 		super.init(parent);
1132 
1133 		this.setActiveFillColor(this._activeFillColor);
1134 		this.setActiveOutlineDash(this._activeOutlineDash);
1135 		this.setActiveOutlineWidth(this._activeOutlineWidth);
1136 		this.setArrowPosition(this._arrowPosition);
1137 		this.setArrowShape(this._arrowShape);
1138 		this.setCapStyle(this._capStyle);
1139 		this.setDisabledFillColor(this._disabledFillColor);
1140 		this.setDisabledOutlineDash(this._disabledOutlineDash);
1141 		this.setDisabledOutlineWidth(this._disabledOutlineWidth);
1142 		this.setFillColor(this._fillColor);
1143 		this.setJoinStyle(this._joinStyle);
1144 		this.setOutlineDash(this._outlineDash);
1145 		this.setOutlineDashOffset(this._outlineDashOffset);
1146 		this.setOutlineWidth(this._outlineWidth);
1147 		this.setSmoothMethod(this._smoothMethod);
1148 		this.setSmoothSplineSteps(this._splineSteps);
1149 	}
1150 
1151 	/**
1152 	 * Mixin common commands.
1153 	 */
1154 	mixin FillColor;
1155 	mixin LineSpecific;
1156 	mixin OutlineDash;
1157 	mixin OutlineWidth;
1158 	mixin Vertex;
1159 }
1160 
1161 /**
1162  * Arrow positions on a canvas line.
1163  */
1164 enum CanvasLineArrow : string
1165 {
1166 	none  = "none",  /// No arrows.
1167 	first = "first", /// Arrows on the first coordinate.
1168 	last  = "last",  /// Arrow on the last coordinate.
1169 	both  = "both",  /// Arrows on both ends.
1170 }
1171 
1172 /**
1173  * The cap styles of a canvas line.
1174  */
1175 enum CanvasLineCapStyle : string
1176 {
1177 	butt       = "butt",       /// The cap is just a butt.
1178 	projecting = "projecting", /// The cap projects beyond the line.
1179 	round      = "round",      /// The cap is rounded.
1180 }
1181 
1182 /**
1183  * The join styles of a canvas line.
1184  */
1185 enum CanvasLineJoinStyle : string
1186 {
1187 	bevel = "bevel", /// The join is bevelled.
1188 	mitre = "miter", /// The join is mitred.
1189 	round = "round", /// The join is round.
1190 }
1191 
1192 /**
1193  * The join styles of a canvas line.
1194  */
1195 enum CanvasLineSmoothMethod : string
1196 {
1197 	none   = "",       /// No smoothing.
1198 	bezier = "bezier", /// Draw the line using the bezier smooth method.
1199 	raw    = "raw",    /// Draw the line using the raw smooth method.
1200 }
1201 
1202 /**
1203  * A canvas rectangle item.
1204  *
1205  * Common_Commands:
1206  *     These are injected common commands that can also be used with this canvas item.
1207  *     $(P
1208  *         $(LINK2 ./common/canvas/fillcolor.html, FillColor) $(BR)
1209  *         $(LINK2 ./common/canvas/outlinecolor.html, OutlineColor) $(BR)
1210  *         $(LINK2 ./common/canvas/outlinedash.html, OutlineDash) $(BR)
1211  *         $(LINK2 ./common/canvas/outlinewidth.html, OutlineWidth) $(BR)
1212  *     )
1213  *
1214  * See_Also:
1215  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
1216  */
1217 class CanvasRectangle : CanvasItem
1218 {
1219 	/**
1220 	 * Create a rectangle from four coordinates.
1221 	 * Use colors from the preset color $(LINK2 ../../color.html, list) or a web style hex color.
1222 	 *
1223 	 * Params:
1224 	 *     coords = The coordinates where to draw the rectangle.
1225 	 *     fillColor = The fill color.
1226 	 *     outlineColor = The outline color.
1227 	 *     outlineWidth = The outline width.
1228 	 *
1229 	 * See_Also:
1230 	 *     $(LINK2 ../element/color.html, tkd.widget.color) $(BR)
1231 	 */
1232 	public this(double[] coords, string fillColor = Color.default_, string outlineColor = Color.black, int outlineWidth = 1)
1233 	{
1234 		assert(coords.length == 4, "Four coordinates are needed to draw a rectangle.");
1235 
1236 		this._type         = "rectangle";
1237 		this._coords       = coords;
1238 		this._fillColor    = fillColor;
1239 		this._outlineColor = outlineColor;
1240 		this._outlineWidth = outlineWidth;
1241 	}
1242 
1243 	/*
1244 	 * Initialise the item.
1245 	 *
1246 	 * Params:
1247 	 *     parent = The parent canvas to initialise against.
1248 	 */
1249 	override protected void init(Canvas parent)
1250 	{
1251 		super.init(parent);
1252 
1253 		this.setActiveFillColor(this._activeFillColor);
1254 		this.setActiveOutlineColor(this._activeOutlineColor);
1255 		this.setActiveOutlineDash(this._activeOutlineDash);
1256 		this.setActiveOutlineWidth(this._activeOutlineWidth);
1257 		this.setDisabledFillColor(this._disabledFillColor);
1258 		this.setDisabledOutlineColor(this._disabledOutlineColor);
1259 		this.setDisabledOutlineDash(this._disabledOutlineDash);
1260 		this.setDisabledOutlineWidth(this._disabledOutlineWidth);
1261 		this.setFillColor(this._fillColor);
1262 		this.setOutlineColor(this._outlineColor);
1263 		this.setOutlineDash(this._outlineDash);
1264 		this.setOutlineDashOffset(this._outlineDashOffset);
1265 		this.setOutlineWidth(this._outlineWidth);
1266 	}
1267 
1268 	/**
1269 	 * Mixin common commands.
1270 	 */
1271 	mixin FillColor;
1272 	mixin OutlineColor;
1273 	mixin OutlineDash;
1274 	mixin OutlineWidth;
1275 }
1276 
1277 /**
1278  * A canvas oval item.
1279  *
1280  * Common_Commands:
1281  *     These are injected common commands that can also be used with this canvas item.
1282  *     $(P
1283  *         $(LINK2 ./common/canvas/fillcolor.html, FillColor) $(BR)
1284  *         $(LINK2 ./common/canvas/outlinecolor.html, OutlineColor) $(BR)
1285  *         $(LINK2 ./common/canvas/outlinedash.html, OutlineDash) $(BR)
1286  *         $(LINK2 ./common/canvas/outlinewidth.html, OutlineWidth) $(BR)
1287  *     )
1288  *
1289  * See_Also:
1290  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
1291  */
1292 class CanvasOval : CanvasItem
1293 {
1294 	/**
1295 	 * Create an oval from four coordinates.
1296 	 * Use colors from the preset color $(LINK2 ../element/color.html, list) or a web style hex color.
1297 	 *
1298 	 * Params:
1299 	 *     coords = The coordinates where to draw the oval.
1300 	 *     fillColor = The fill color.
1301 	 *     outlineColor = The outline color.
1302 	 *     outlineWidth = The outline width.
1303 	 *
1304 	 * See_Also:
1305 	 *     $(LINK2 ../element/color.html, tkd.widget.color) $(BR)
1306 	 */
1307 	public this(double[] coords, string fillColor = Color.default_, string outlineColor = Color.black, int outlineWidth = 1)
1308 	{
1309 		assert(coords.length == 4, "Four coordinates are needed to draw an oval.");
1310 
1311 		this._type         = "oval";
1312 		this._coords       = coords;
1313 		this._fillColor    = fillColor;
1314 		this._outlineColor = outlineColor;
1315 		this._outlineWidth = outlineWidth;
1316 	}
1317 
1318 	/*
1319 	 * Initialise the item.
1320 	 *
1321 	 * Params:
1322 	 *     parent = The parent canvas to initialise against.
1323 	 */
1324 	override protected void init(Canvas parent)
1325 	{
1326 		super.init(parent);
1327 
1328 		this.setActiveFillColor(this._activeFillColor);
1329 		this.setActiveOutlineColor(this._activeOutlineColor);
1330 		this.setActiveOutlineDash(this._activeOutlineDash);
1331 		this.setActiveOutlineWidth(this._activeOutlineWidth);
1332 		this.setDisabledFillColor(this._disabledFillColor);
1333 		this.setDisabledOutlineColor(this._disabledOutlineColor);
1334 		this.setDisabledOutlineDash(this._disabledOutlineDash);
1335 		this.setDisabledOutlineWidth(this._disabledOutlineWidth);
1336 		this.setFillColor(this._fillColor);
1337 		this.setOutlineColor(this._outlineColor);
1338 		this.setOutlineDash(this._outlineDash);
1339 		this.setOutlineDashOffset(this._outlineDashOffset);
1340 		this.setOutlineWidth(this._outlineWidth);
1341 	}
1342 
1343 	/**
1344 	 * Mixin common commands.
1345 	 */
1346 	mixin FillColor;
1347 	mixin OutlineColor;
1348 	mixin OutlineDash;
1349 	mixin OutlineWidth;
1350 }
1351 
1352 /**
1353  * A canvas polygon item.
1354  *
1355  * Common_Commands:
1356  *     These are injected common commands that can also be used with this canvas item.
1357  *     $(P
1358  *         $(LINK2 ./common/canvas/fillcolor.html, FillColor) $(BR)
1359  *         $(LINK2 ./common/canvas/outlinecolor.html, OutlineColor) $(BR)
1360  *         $(LINK2 ./common/canvas/outlinedash.html, OutlineDash) $(BR)
1361  *         $(LINK2 ./common/canvas/outlinewidth.html, OutlineWidth) $(BR)
1362  *         $(LINK2 ./common/canvas/vertex.html, Vertex) $(BR)
1363  *     )
1364  *
1365  * See_Also:
1366  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
1367  */
1368 class CanvasPolygon : CanvasItem
1369 {
1370 	/**
1371 	 * Create a polygon from coordinates.
1372 	 * Use colors from the preset color $(LINK2 ../element/color.html, list) or a web style hex color.
1373 	 *
1374 	 * Params:
1375 	 *     coords = The coordinates where to draw the polygon.
1376 	 *     fillColor = The fill color.
1377 	 *     outlineColor = The outline color.
1378 	 *     outlineWidth = The outline width.
1379 	 *
1380 	 * See_Also:
1381 	 *     $(LINK2 ../element/color.html, tkd.widget.color) $(BR)
1382 	 */
1383 	public this(double[] coords, string fillColor = Color.default_, string outlineColor = Color.black, int outlineWidth = 1)
1384 	{
1385 		assert(coords.length >= 3, "Three or more coordinates are needed to draw a polygon.");
1386 
1387 		this._type         = "polygon";
1388 		this._coords       = coords;
1389 		this._fillColor    = fillColor;
1390 		this._outlineColor = outlineColor;
1391 		this._outlineWidth = outlineWidth;
1392 	}
1393 
1394 	/*
1395 	 * Initialise the item.
1396 	 *
1397 	 * Params:
1398 	 *     parent = The parent canvas to initialise against.
1399 	 */
1400 	override protected void init(Canvas parent)
1401 	{
1402 		super.init(parent);
1403 
1404 		this.setActiveFillColor(this._activeFillColor);
1405 		this.setActiveOutlineColor(this._activeOutlineColor);
1406 		this.setActiveOutlineDash(this._activeOutlineDash);
1407 		this.setActiveOutlineWidth(this._activeOutlineWidth);
1408 		this.setDisabledFillColor(this._disabledFillColor);
1409 		this.setDisabledOutlineColor(this._disabledOutlineColor);
1410 		this.setDisabledOutlineDash(this._disabledOutlineDash);
1411 		this.setDisabledOutlineWidth(this._disabledOutlineWidth);
1412 		this.setFillColor(this._fillColor);
1413 		this.setJoinStyle(this._joinStyle);
1414 		this.setOutlineColor(this._outlineColor);
1415 		this.setOutlineDash(this._outlineDash);
1416 		this.setOutlineDashOffset(this._outlineDashOffset);
1417 		this.setOutlineWidth(this._outlineWidth);
1418 		this.setSmoothMethod(this._smoothMethod);
1419 		this.setSmoothSplineSteps(this._splineSteps);
1420 	}
1421 
1422 	/**
1423 	 * Mixin common commands.
1424 	 */
1425 	mixin FillColor;
1426 	mixin OutlineColor;
1427 	mixin OutlineDash;
1428 	mixin OutlineWidth;
1429 	mixin Vertex;
1430 }
1431 
1432 /**
1433  * A canvas text item.
1434  *
1435  * Common_Commands:
1436  *     These are injected common commands that can also be used with this canvas item.
1437  *     $(P
1438  *         $(LINK2 ./common/canvas/anchor.html, Anchor) $(BR)
1439  *         $(LINK2 ./common/canvas/fillcolor.html, FillColor) $(BR)
1440  *         $(LINK2 ./common/canvas/textspecific.html, TextSpecific) $(BR)
1441  *     )
1442  *
1443  * See_Also:
1444  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
1445  */
1446 class CanvasText : CanvasItem
1447 {
1448 	/**
1449 	 * Create a text item.
1450 	 * Use colors from the preset color $(LINK2 ../element/color.html, list) or a web style hex color.
1451 	 *
1452 	 * Params:
1453 	 *     coords = The coordinates where to draw the polygon.
1454 	 *     text = The text.
1455 	 *     fillColor = The fill color.
1456 	 *     anchor = The anchor position of the image.
1457 	 *
1458 	 * See_Also:
1459 	 *     $(LINK2 ../element/color.html, tkd.widget.color) $(BR)
1460 	 */
1461 	public this(double[] coords, string text, string fillColor = Color.default_, string anchor = AnchorPosition.northWest)
1462 	{
1463 		assert(coords.length == 2, "Two coordinates are needed to position text.");
1464 
1465 		this._type      = "text";
1466 		this._coords    = coords;
1467 		this._text      = text;
1468 		this._fillColor = fillColor;
1469 		this._anchor    = anchor;
1470 	}
1471 
1472 	/*
1473 	 * Initialise the item.
1474 	 *
1475 	 * Params:
1476 	 *     parent = The parent canvas to initialise against.
1477 	 */
1478 	override protected void init(Canvas parent)
1479 	{
1480 		super.init(parent);
1481 
1482 		this.setActiveFillColor(this._activeFillColor);
1483 		this.setAlignment(this._alignment);
1484 		this.setAnchor(this._anchor);
1485 		this.setAngle(this._angle);
1486 		this.setDisabledFillColor(this._disabledFillColor);
1487 		this.setFillColor(this._fillColor);
1488 		this.setFont(this._font);
1489 		this.setMaxLineLength(this._maxLineLength);
1490 		this.setText(this._text);
1491 	}
1492 
1493 	/**
1494 	 * Mixin common commands.
1495 	 */
1496 	mixin Anchor;
1497 	mixin FillColor;
1498 	mixin TextSpecific;
1499 }
1500 
1501 /**
1502  * A canvas widget item.
1503  *
1504  * Common_Commands:
1505  *     These are injected common commands that can also be used with this canvas item.
1506  *     $(P
1507  *         $(LINK2 ./common/canvas/anchor.html, Anchor) $(BR)
1508  *         $(LINK2 ./common/canvas/widgetspecific.html, WidgetSpecific) $(BR)
1509  *     )
1510  *
1511  * See_Also:
1512  *     $(LINK2 ./canvas.html#CanvasItem, tkd.widget.canvas.CanvasItem)
1513  */
1514 class CanvasWidget : CanvasItem
1515 {
1516 	/**
1517 	 * Create a widget item.
1518 	 *
1519 	 * Params:
1520 	 *     coords = The coordinates where to draw the polygon.
1521 	 *     widget = The widget to use.
1522 	 *     anchor = The anchor position of the image.
1523 	 */
1524 	public this(double[] coords, Widget widget, string anchor = AnchorPosition.northWest)
1525 	{
1526 		assert(coords.length == 2, "Two coordinates are needed to position a widget.");
1527 
1528 		this._type   = "window";
1529 		this._coords = coords;
1530 		this._widget = widget;
1531 		this._anchor = anchor;
1532 	}
1533 
1534 	/*
1535 	 * Initialise the item.
1536 	 *
1537 	 * Params:
1538 	 *     parent = The parent canvas to initialise against.
1539 	 */
1540 	override protected void init(Canvas parent)
1541 	{
1542 		super.init(parent);
1543 
1544 		this.setAnchor(this._anchor);
1545 		this.setHeight(this._height);
1546 		this.setWidget(this._widget);
1547 		this.setWidth(this._width);
1548 	}
1549 
1550 	/**
1551 	 * Mixin common commands.
1552 	 */
1553 	mixin Anchor;
1554 	mixin WidgetSpecific;
1555 }