1 /**
2  * Element module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.element.uielement;
8 
9 /**
10  * Imports.
11  */
12 import std.algorithm;
13 import std.conv;
14 import std.range;
15 import std.regex : match;
16 import std..string;
17 import tkd.element.cursor;
18 import tkd.element.element;
19 
20 /**
21  * The ui element base class.
22  *
23  * See_Also:
24  *     $(LINK2 ./element.html, tkd.element.element)
25  */
26 abstract class UiElement : Element
27 {
28 	/**
29 	 * Construct the element.
30 	 *
31 	 * Params:
32 	 *     parent = An optional parent of this element.
33 	 */
34 	public this(UiElement parent = null)
35 	{
36 		super(parent);
37 	}
38 
39 	/**
40 	 * Get the widget's class.
41 	 *
42 	 * Returns:
43 	 *     The widget's class as a string.
44 	 *
45 	 * See_Also:
46 	 *     $(LINK2 ./elementclass.html, tkd.element.elementclass) for returned classes.
47 	 */
48 	public string getClass()
49 	{
50 		this._tk.eval(format("%s cget -class", this.id));
51 		if (this._tk.getResult!(string).empty())
52 		{
53 			this._tk.eval(format("winfo class %s", this.id));
54 		}
55 		return this._tk.getResult!(string);
56 	}
57 
58 	/**
59 	 * Set the widget's cursor.
60 	 *
61 	 * Params:
62 	 *     cursor = Any valid widget cursor.
63 	 *
64 	 * Returns:
65 	 *     This widget to aid method chaining.
66 	 *
67 	 * See_Also:
68 	 *     $(LINK2 ./cursor.html, tkd.element.cursor) for supported cursors.
69 	 */
70 	public auto setCursor(this T)(string cursor)
71 	{
72 		this._tk.eval(format("%s configure -cursor %s", this.id, cursor));
73 
74 		return cast(T) this;
75 	}
76 
77 	/**
78 	 * Get the widget's cursor.
79 	 *
80 	 * Returns:
81 	 *     The widget's cursor.
82 	 *
83 	 * See_Also:
84 	 *     $(LINK2 ./cursor.html, tkd.element.cursor) for returned cursors.
85 	 */
86 	public string getCursor()
87 	{
88 		this._tk.eval(format("%s cget -cursor", this.id));
89 		return this._tk.getResult!(string);
90 	}
91 
92 	/**
93 	 * Bind a callback to a particular event triggered by this element.
94 	 *
95 	 * Params:
96 	 *     binding = The binding that triggers this event. See below.
97 	 *     callback = The delegate callback to execute when the event triggers.
98 	 *
99 	 * Returns:
100 	 *     This widget to aid method chaining.
101 	 *
102 	 * Bindings:
103 	 *     The binding argument specifies a sequence of one or more event 
104 	 *     patterns, with optional white space between the patterns. Each event 
105 	 *     pattern may take one of three forms. In the simplest case it is a 
106 	 *     single printing ASCII character, such as a or [. The character may 
107 	 *     not be a space character or the character <. This form of pattern 
108 	 *     matches a KeyPress event for the particular character. The second 
109 	 *     form of pattern is longer but more general. It has the following 
110 	 *     syntax.
111 	 *     ----
112 	 *     <modifier-modifier-type-detail>
113 	 *     ----
114 	 *     The entire event pattern is surrounded by angle brackets. Inside the 
115 	 *     angle brackets are zero or more modifiers, an event type, and an 
116 	 *     extra piece of information (detail) identifying a particular button 
117 	 *     or keysym. Any of the fields may be omitted, as long as at least one 
118 	 *     of type and detail is present. The fields must be separated by white 
119 	 *     space or dashes (dashes are prefered). The third form of pattern is 
120 	 *     used to specify a user-defined, named virtual event. It has the 
121 	 *     following syntax.
122 	 *     ----
123 	 *     <<name>>
124 	 *     ----
125 	 *     The entire virtual event pattern is surrounded by double angle 
126 	 *     brackets. Inside the angle brackets is the user-defined name of the 
127 	 *     virtual event. Modifiers, such as Shift or Control, may not be 
128 	 *     combined with a virtual event to modify it. Bindings on a virtual 
129 	 *     event may be created before the virtual event is defined, and if the 
130 	 *     definition of a virtual event changes dynamically, all windows bound 
131 	 *     to that virtual event will respond immediately to the new 
132 	 *     definition. Some widgets (e.g. menu and text) issue virtual events 
133 	 *     when their internal state is updated in some ways. Please see the 
134 	 *     documentation for each widget for details.
135 	 *
136 	 * Event_Modifiers:
137 	 *     $(P
138 	 *         $(PARAM_TABLE
139 	 *             $(PARAM_ROW &lt;Alt&gt;, The Alt key.)
140 	 *             $(PARAM_ROW &lt;Button1&gt; $(BR) &lt;B1&gt;, Mouse button one.)
141 	 *             $(PARAM_ROW &lt;Button2&gt; $(BR) &lt;B2&gt;, Mouse button two.)
142 	 *             $(PARAM_ROW &lt;Button3&gt; $(BR) &lt;B3&gt;, Mouse button three.)
143 	 *             $(PARAM_ROW &lt;Button3&gt; $(BR) &lt;B5&gt;, Mouse button five.)
144 	 *             $(PARAM_ROW &lt;Button4&gt; $(BR) &lt;B4&gt;, Mouse button four.)
145 	 *             $(PARAM_ROW &lt;Control&gt;, The Ctrl key.)
146 	 *             $(PARAM_ROW &lt;Double&gt;, Modifier for doing something twice.)
147 	 *             $(PARAM_ROW &lt;Extended&gt;, Extended keyboard support.)
148 	 *             $(PARAM_ROW &lt;Lock&gt;, Unknown.)
149 	 *             $(PARAM_ROW &lt;Meta&gt; $(BR) &lt;M&gt;, The meta key.)
150 	 *             $(PARAM_ROW &lt;Mod1&gt; $(BR) &lt;M1&gt; $(BR) &lt;Command&gt;, First modifier key.)
151 	 *             $(PARAM_ROW &lt;Mod2&gt; $(BR) &lt;M2&gt; $(BR) &lt;Option&gt;, Second modifier key.)
152 	 *             $(PARAM_ROW &lt;Mod3&gt; $(BR) &lt;M3&gt;, Third modifier key.)
153 	 *             $(PARAM_ROW &lt;Mod4&gt; $(BR) &lt;M4&gt;, Fourth modifier key.)
154 	 *             $(PARAM_ROW &lt;Mod5&gt; $(BR) &lt;M5&gt;, Fifth modifier key.)
155 	 *             $(PARAM_ROW &lt;Quadruple&gt;, Modifier for doing something four times.)
156 	 *             $(PARAM_ROW &lt;Shift&gt;, The Shift key.)
157 	 *             $(PARAM_ROW &lt;Triple&gt;, Modifier for doing something three times.)
158 	 *         )
159 	 *     )
160 	 *     Where more than one value is listed, the values are equivalent. Most 
161 	 *     of the modifiers have the obvious meanings. For example, Button1 
162 	 *     requires that button 1 be depressed when the event occurs. For a 
163 	 *     binding to match a given event, the modifiers in the event must 
164 	 *     include all of those specified in the event pattern. An event may 
165 	 *     also contain additional modifiers not specified in the binding. For 
166 	 *     example, if button 1 is pressed while the shift and control keys are 
167 	 *     down, the pattern $(B &lt;Control-Button-1&gt;) will match the 
168 	 *     event, but $(B &lt;Mod1-Button-1&gt;) will not. If no modifiers are 
169 	 *     specified, then any combination of modifiers may be present in the 
170 	 *     event.
171 	 *
172 	 *     Meta and M refer to whichever of the M1 through M5 modifiers is 
173 	 *     associated with the Meta key(s) on the keyboard. If there are no 
174 	 *     Meta keys, or if they are not associated with any modifiers, then 
175 	 *     Meta and M will not match any events. Similarly, the Alt modifier 
176 	 *     refers to whichever modifier is associated with the alt key(s) on 
177 	 *     the keyboard.
178 	 *
179 	 *     The Double, Triple and Quadruple modifiers are a convenience for 
180 	 *     specifying double mouse clicks and other repeated events. They cause 
181 	 *     a particular event pattern to be repeated 2, 3 or 4 times, and also 
182 	 *     place a time and space requirement on the sequence: for a sequence 
183 	 *     of events to match a Double, Triple or Quadruple pattern, all of the 
184 	 *     events must occur close together in time and without substantial 
185 	 *     mouse motion in between. For example, $(B &lt;Double-Button-1&gt;) 
186 	 *     is equivalent to $(B &lt;Button-1&gt;&lt;Button-1&gt;) with the 
187 	 *     extra time and space requirement.
188 	 *
189 	 *     The Command and Option modifiers correspond to Macintosh-specific 
190 	 *     modifier keys.
191 	 *
192 	 *     The Extended modifier is, at present, specific to Windows. It 
193 	 *     appears on events that are associated with the keys on the 'extended 
194 	 *     keyboard'. On a US keyboard, the extended keys include the Alt and 
195 	 *     Control keys at the right of the keyboard, the cursor keys in the 
196 	 *     cluster to the left of the numeric pad, the NumLock key, the 
197 	 *     Break key, the PrintScreen key, and the / and Enter keys in the 
198 	 *     numeric keypad.
199 	 *
200 	 * Event_Types:
201 	 *     $(P
202 	 *         $(PARAM_TABLE
203 	 *             $(PARAM_ROW &lt;Activate&gt; $(BR) &lt;Deactivate&gt;, These two events are sent to every sub-window of a toplevel when they change state. In addition to the focus Window the Macintosh platform and Windows platforms have a notion of an active window (which often has but is not required to have the focus). On the Macintosh widgets in the active window have a different appearance than widgets in deactive windows. The Activate event is sent to all the sub-windows in a toplevel when it changes from being deactive to active. Likewise the Deactive event is sent when the window's state changes from active to deactive. There are no useful percent substitutions you would make when binding to these events.)
204 	 *             $(PARAM_ROW &lt;MouseWheel&gt;, Some mice on the Windows platform support a mouse wheel which is used for scrolling documents without using the scrollbars. By rolling the wheel the system will generate MouseWheel events that the application can use to scroll. On Windows the event is always routed to the window that currently has focus (like Key events.) On Mac OS X the event is routed to the window under the pointer. When the event is received you can use the %D substitution to get the delta field for the event which is a integer value describing how the mouse wheel has moved. The smallest value for which the system will report is defined by the OS. On Windows 95 & 98 machines this value is at least 120 before it is reported. However higher resolution devices may be available in the future. On Mac OS X the value is not scaled by 120 but a value of 1 corresponds to roughly one text line. The sign of the value determines which direction your widget should scroll. Positive values should scroll up and negative values should scroll down.)
205 	 *             $(PARAM_ROW &lt;KeyPress&gt; $(BR) &lt;KeyRelease&gt;, The KeyPress and KeyRelease events are generated whenever a key is pressed or released. KeyPress and KeyRelease events are sent to the UI element which currently has the keyboard focus.)
206 	 *             $(PARAM_ROW &lt;ButtonPress&gt; $(BR) &lt;ButtonRelease&gt; $(BR) &lt;Motion&gt;, The ButtonPress and ButtonRelease events are generated when the user presses or releases a mouse button. Motion events are generated whenever the pointer is moved. ButtonPress ButtonRelease and Motion events are normally sent to the window containing the pointer. When a mouse button is pressed the window containing the pointer automatically obtains a temporary pointer grab. Subsequent ButtonPress ButtonRelease and Motion events will be sent to that window regardless of which window contains the pointer until all buttons have been released.)
207 	 *             $(PARAM_ROW &lt;Configure&gt;, A Configure event is sent to a window whenever its size position or border width changes and sometimes when it has changed position in the stacking order.)
208 	 *             $(PARAM_ROW &lt;Map&gt; $(BR) &lt;Unmap&gt;, The Map and Unmap events are generated whenever the mapping state of a window changes. Windows are created in the unmapped state. Top-level windows become mapped when they transition to the normal state and are unmapped in the withdrawn and iconic states. Other windows become mapped when they are placed under control of a geometry manager (for example pack or grid). A window is viewable only if it and all of its ancestors are mapped. Note that geometry managers typically do not map their children until they have been mapped themselves and unmap all children when they become unmapped; hence in Tk Map and Unmap events indicate whether or not a window is viewable.)
209 	 *             $(PARAM_ROW &lt;Visibility&gt;, A window is said to be obscured when another window above it in the stacking order fully or partially overlaps it. Visibility events are generated whenever a window's obscurity state changes; the state field (%s) specifies the new state.)
210 	 *             $(PARAM_ROW &lt;Expose&gt;, An Expose event is generated whenever all or part of a window should be redrawn (for example when a window is first mapped or if it becomes unobscured). It is normally not necessary for client applications to handle Expose events since Tk handles them internally.)
211 	 *             $(PARAM_ROW &lt;Destroy&gt;, A Destroy event is delivered to a window when it is destroyed. When the Destroy event is delivered to a widget it is in a 'half-dead' state: the widget still exists but most operations on it will fail.)
212 	 *             $(PARAM_ROW &lt;FocusIn&gt; $(BR) &lt;FocusOut&gt;, The FocusIn and FocusOut events are generated whenever the keyboard focus changes. A FocusOut event is sent to the old focus window and a FocusIn event is sent to the new one. In addition if the old and new focus windows do not share a common parent 'virtual crossing' focus events are sent to the intermediate windows in the hierarchy. Thus a FocusIn event indicates that the target window or one of its descendants has acquired the focus and a FocusOut event indicates that the focus has been changed to a window outside the target window's hierarchy. The keyboard focus may be changed explicitly by a call to focus or implicitly by the window manager.)
213 	 *             $(PARAM_ROW &lt;Enter&gt; $(BR) &lt;Leave&gt;, An Enter event is sent to a window when the pointer enters that window and a Leave event is sent when the pointer leaves it. If there is a pointer grab in effect Enter and Leave events are only delivered to the window owning the grab. In addition when the pointer moves between two windows Enter and Leave 'virtual crossing' events are sent to intermediate windows in the hierarchy in the same manner as for FocusIn and FocusOut events.)
214 	 *             $(PARAM_ROW &lt;Property&gt;, A Property event is sent to a window whenever an X property belonging to that window is changed or deleted. Property events are not normally delivered to Tk applications as they are handled by the Tk core.)
215 	 *             $(PARAM_ROW &lt;Colormap&gt;, A Colormap event is generated whenever the colormap associated with a window has been changed installed or uninstalled. Widgets may be assigned a private colormap by specifying a -colormap option; the window manager is responsible for installing and uninstalling colormaps as necessary.)
216 	 *             $(PARAM_ROW &lt;CirculateRequest&gt; $(BR) &lt;ConfigureRequest&gt; $(BR) &lt;Create&gt; $(BR) &lt;MapRequest&gt; $(BR) &lt;ResizeRequest&gt;, A Colormap event is generated whenever the colormap associated with a window has been changed installed or uninstalled. Widgets may be assigned a private colormap by specifying a -colormap option; the window manager is responsible for installing and uninstalling colormaps as necessary. Note that Tk provides no useful details for this event type.)
217 	 *             $(PARAM_ROW &lt;Circulate&gt; $(BR) &lt;Gravity&gt; $(BR) &lt;Reparent&gt;, The events Gravity and Reparent are not normally delivered to Tk applications. They are included for completeness. A Circulate event indicates that the window has moved to the top or to the bottom of the stacking order as a result of an XCirculateSubwindows protocol request. Note that the stacking order may be changed for other reasons which do not generate a Circulate event, and that Tk does not use XCirculateSubwindows() internally. This event type is included only for completeness; there is no reliable way to track changes to a window's position in the stacking order.)
218 	 *         )
219 	 *     )
220 	 *
221 	 * Event_Details:
222 	 *     The last part of a long event specification is detail. In the case 
223 	 *     of a ButtonPress or ButtonRelease event, it is the number of a 
224 	 *     button (1-5). If a button number is given, then only an event on 
225 	 *     that particular button will match; if no button number is given, 
226 	 *     then an event on any button will match. Note: giving a specific 
227 	 *     button number is different than specifying a button 
228 	 *     modifier; in the first case, it refers to a button being 
229 	 *     pressed or released, while in the second it refers to some 
230 	 *     other button that is already depressed when the matching 
231 	 *     event occurs. If a button number is given then type may be 
232 	 *     omitted; if will default to ButtonPress. For example, the 
233 	 *     specifier $(B &lt;1&gt;) is equivalent to $(B &lt;ButtonPress-1&gt;).
234 	 *
235 	 *     If the event type is KeyPress or KeyRelease, then detail may be 
236 	 *     specified in the form of an X keysym. Keysyms are textual 
237 	 *     specifications for particular keys on the keyboard; they include all 
238 	 *     the alphanumeric ASCII characters (e.g. “a” is the keysym for the 
239 	 *     ASCII character “a”), plus descriptions for non-alphanumeric 
240 	 *     characters (“comma”is the keysym for the comma character), plus 
241 	 *     descriptions for all the non-ASCII keys on the keyboard (e.g. 
242 	 *     “Shift_L” is the keysym for the left shift key, and “F1” is 
243 	 *     the keysym for the F1 function key, if it exists). The 
244 	 *     complete list of keysyms is not presented here; it is available in 
245 	 *     other X documentation and may vary from system to system. If a 
246 	 *     keysym detail is given, then the type field may be omitted; it will 
247 	 *     default to KeyPress. For example, $(B &lt;Control-comma&gt;) is 
248 	 *     equivalent to $(B &lt;Control-KeyPress-comma&gt;).
249 	 *
250 	 * Virtual_Events:
251 	 *     The following are built-in virtual events for the purposes of notification:
252 	 *     $(P
253 	 *         $(PARAM_TABLE
254 	 *             $(PARAM_ROW &lt;&lt;AltUnderlined&gt;&gt;, This is sent to widget to notify it that the letter it has underlined (as an accelerator indicator) with the -underline option has been pressed in combination with the Alt key. The usual response to this is to either focus into the widget (or some related widget) or to invoke the widget.)
255 	 *             $(PARAM_ROW &lt;&lt;Invoke&gt;&gt;, This can be sent to some widgets (e.g. button, listbox, menu) as an alternative to &lt;space&gt;.)
256 	 *             $(PARAM_ROW &lt;&lt;ListboxSelect&gt;&gt;, This is sent to a listbox when the set of selected item(s) in the listbox is updated.)
257 	 *             $(PARAM_ROW &lt;&lt;MenuSelect&gt;&gt;, This is sent to a menu when the currently selected item in the menu changes. It is intended for use with context-sensitive help systems.)
258 	 *             $(PARAM_ROW &lt;&lt;Modified&gt;&gt;, This is sent to a text widget when the contents of the widget are changed.)
259 	 *             $(PARAM_ROW &lt;&lt;Selection&gt;&gt;, This is sent to a text widget when the selection in the widget is changed.)
260 	 *             $(PARAM_ROW &lt;&lt;ThemeChanged&gt;&gt;, This is sent to a text widget when the ttk (Tile) theme changed.)
261 	 *             $(PARAM_ROW &lt;&lt;TraverseIn&gt;&gt;, This is sent to a widget when the focus enters the widget because of a user-driven “tab to widget” action.)
262 	 *             $(PARAM_ROW &lt;&lt;TraverseOut&gt;&gt;, This is sent to a widget when the focus leaves the widget because of a user-driven “tab to widget” action.)
263 	 *         )
264 	 *     )
265 	 *     The following are built-in virtual events for the purposes of unifying bindings across multiple platforms.
266 	 *     $(P
267 	 *         $(PARAM_TABLE
268 	 *             $(PARAM_ROW &lt;&lt;Clear&gt;&gt;, Delete the currently selected widget contents.)
269 	 *             $(PARAM_ROW &lt;&lt;Copy&gt;&gt;, Copy the currently selected widget contents to the clipboard.)
270 	 *             $(PARAM_ROW &lt;&lt;Cut&gt;&gt;, Move the currently selected widget contents to the clipboard.)
271 	 *             $(PARAM_ROW &lt;&lt;LineEnd&gt;&gt;, Move to the end of the line in the current widget while deselecting any selected contents.)
272 	 *             $(PARAM_ROW &lt;&lt;LineStart&gt;&gt;, Move to the start of the line in the current widget while deselecting any selected contents.)
273 	 *             $(PARAM_ROW &lt;&lt;NextChar&gt;&gt;, Move to the next item (i.e., visible character) in the current widget while deselecting any selected contents.)
274 	 *             $(PARAM_ROW &lt;&lt;NextLine&gt;&gt;, Move to the next line in the current widget while deselecting any selected contents.)
275 	 *             $(PARAM_ROW &lt;&lt;NextPara&gt;&gt;, Move to the next paragraph in the current widget while deselecting any selected contents.)
276 	 *             $(PARAM_ROW &lt;&lt;NextWord&gt;&gt;, Move to the next group of items (i.e., visible word) in the current widget while deselecting any selected contents.)
277 	 *             $(PARAM_ROW &lt;&lt;Paste&gt;&gt;, Replace the currently selected widget contents with the contents of the clipboard.)
278 	 *             $(PARAM_ROW &lt;&lt;PasteSelection&gt;&gt;, Insert the contents of the selection at the mouse location. (This event has meaningful %x and %y substitutions).)
279 	 *             $(PARAM_ROW &lt;&lt;PrevChar&gt;&gt;, Move to the previous item (i.e., visible character) in the current widget while deselecting any selected contents.)
280 	 *             $(PARAM_ROW &lt;&lt;PrevLine&gt;&gt;, Move to the previous line in the current widget while deselecting any selected contents.)
281 	 *             $(PARAM_ROW &lt;&lt;PrevPara&gt;&gt;, Move to the previous paragraph in the current widget while deselecting any selected contents.)
282 	 *             $(PARAM_ROW &lt;&lt;PrevWindow&gt;&gt;, Traverse to the previous window.)
283 	 *             $(PARAM_ROW &lt;&lt;PrevWord&gt;&gt;, Move to the previous group of items (i.e., visible word) in the current widget while deselecting any selected contents.)
284 	 *             $(PARAM_ROW &lt;&lt;Redo&gt;&gt;, Redo one undone action.)
285 	 *             $(PARAM_ROW &lt;&lt;SelectAll&gt;&gt;, Set the range of selected contents to the complete widget.)
286 	 *             $(PARAM_ROW &lt;&lt;SelectLineEnd&gt;&gt;, Move to the end of the line in the current widget while extending the range of selected contents.)
287 	 *             $(PARAM_ROW &lt;&lt;SelectLineStart&gt;&gt;, Move to the start of the line in the current widget while extending the range of selected contents.)
288 	 *             $(PARAM_ROW &lt;&lt;SelectNextChar&gt;&gt;, Move to the next item (i.e., visible character) in the current widget while extending the range of selected contents.)
289 	 *             $(PARAM_ROW &lt;&lt;SelectNextLine&gt;&gt;, Move to the next line in the current widget while extending the range of selected contents.)
290 	 *             $(PARAM_ROW &lt;&lt;SelectNextPara&gt;&gt;, Move to the next paragraph in the current widget while extending the range of selected contents.)
291 	 *             $(PARAM_ROW &lt;&lt;SelectNextWord&gt;&gt;, Move to the next group of items (i.e., visible word) in the current widget while extending the range of selected contents.)
292 	 *             $(PARAM_ROW &lt;&lt;SelectNone&gt;&gt;, Reset the range of selected contents to be empty.)
293 	 *             $(PARAM_ROW &lt;&lt;SelectPrevChar&gt;&gt;, Move to the previous item (i.e., visible character) in the current widget while extending the range of selected contents.)
294 	 *             $(PARAM_ROW &lt;&lt;SelectPrevLine&gt;&gt;, Move to the previous line in the current widget while extending the range of selected contents.)
295 	 *             $(PARAM_ROW &lt;&lt;SelectPrevPara&gt;&gt;, Move to the previous paragraph in the current widget while extending the range of selected contents.)
296 	 *             $(PARAM_ROW &lt;&lt;SelectPrevWord&gt;&gt;, Move to the previous group of items (i.e., visible word) in the current widget while extending the range of selected contents.)
297 	 *             $(PARAM_ROW &lt;&lt;ToggleSelection&gt;&gt;, Toggle the selection.)
298 	 *             $(PARAM_ROW &lt;&lt;Undo&gt;&gt;, Undo the last action.)
299 	 *         )
300 	 *     )
301 	 *
302 	 * Callback_Arguments:
303 	 *     These are the fields within the callback's $(LINK2 
304 	 *     ./element.html#CommandArgs, CommandArgs) parameter which 
305 	 *     are populated by this method when the callback is executed. 
306 	 *     $(P
307 	 *         $(PARAM_TABLE
308 	 *             $(PARAM_ROW CommandArgs.element, The element that executed the callback.)
309 	 *             $(PARAM_ROW CommandArgs.uniqueData, The binding that was responded to.)
310 	 *             $(PARAM_ROW CommandArgs.callback, The callback which was executed.)
311 	 *             $(PARAM_ROW CommandArgs.event.button, The number of any button that was pressed.)
312 	 *             $(PARAM_ROW CommandArgs.event.keyCode, The key code of any key pressed.)
313 	 *             $(PARAM_ROW CommandArgs.event.x, The horizontal position of the mouse relative to the widget.)
314 	 *             $(PARAM_ROW CommandArgs.event.y, The vertical position of the mouse relative to the widget.)
315 	 *             $(PARAM_ROW CommandArgs.event.wheel, Mouse wheel delta.)
316 	 *             $(PARAM_ROW CommandArgs.event.key, Key symbol of any key pressed.)
317 	 *             $(PARAM_ROW CommandArgs.event.screenX, The horizontal position of the mouse relative to the screen.)
318 	 *             $(PARAM_ROW CommandArgs.event.screenY, The vertical position of the mouse relative to the screen.)
319 	 *         )
320 	 *     )
321 	 *
322 	 * See_Also:
323 	 *     $(LINK2 ../tkdapplication.html#TkdApplication.addVirtualEvent, tkd.tkdapplication.TkdApplication.addVirtualEvent) $(BR)
324 	 *     $(LINK2 ../tkdapplication.html#TkdApplication.deleteVirtualEvent, tkd.tkdapplication.TkdApplication.deleteVirtualEvent) $(BR)
325 	 *     $(LINK2 ./element.html#CommandCallback, tkd.element.element.CommandCallback) $(BR)
326 	 *     $(LINK2 ./uielement.html#UiElement.generateEvent, tkd.element.element.UiElement.generateEvent) $(BR)
327 	 */
328 	public auto bind(this T)(string binding, CommandCallback callback)
329 	{
330 		assert(!match(binding, r"^<.*?>$").empty, "Binding must take the form of <binding>");
331 
332 		string command = this.createCommand(callback, binding);
333 		this._tk.eval("bind %s {%s} {%s %%b %%k %%x %%y %%D %%K %%X %%Y}", this.id, binding, command);
334 
335 		return cast(T) this;
336 	}
337 
338 	/**
339 	 * Unbind a previous event binding.
340 	 *
341 	 * Params:
342 	 *     binding = The binding to remove.
343 	 *
344 	 * Returns:
345 	 *     This widget to aid method chaining.
346 	 */
347 	public auto unbind(this T)(string binding)
348 	{
349 		this._tk.deleteCommand(this.getCommandName(binding));
350 		this._tk.eval("bind %s {%s} {}", this.id, binding);
351 
352 		return cast(T) this;
353 	}
354 
355 	/**
356 	 * Destroy this element and remove it from the GUI.
357 	 *
358 	 * Caveats:
359 	 *     Once an element is destroyed it can no longer be referenced in your 
360 	 *     code or a segmentation fault will occur and potentially crash your 
361 	 *     program.
362 	 */
363 	public void destroy()
364 	{
365 		this._tk.eval("destroy %s", this.id);
366 		super.destroy();
367 	}
368 
369 	/**
370 	 * Get the string id's of the immediate children elements.
371 	 *
372 	 * Returns:
373 	 *     A string array containing the id's.
374 	 */
375 	public string[] getChildIds()
376 	{
377 		this._tk.eval("winfo children %s", this.id);
378 
379 		return this._tk.getResult!(string).split();
380 	}
381 
382 	/**
383 	 * Get the width of the element.
384 	 *
385 	 * Returns:
386 	 *     The width of the element.
387 	 */
388 	public int getWidth()
389 	{
390 		this._tk.eval("winfo width %s", this.id);
391 
392 		return this._tk.getResult!(int);
393 	}
394 
395 	/**
396 	 * Get the height of the element.
397 	 *
398 	 * Returns:
399 	 *     The height of the element.
400 	 */
401 	public int getHeight()
402 	{
403 		this._tk.eval("winfo height %s", this.id);
404 
405 		return this._tk.getResult!(int);
406 	}
407 
408 	/**
409 	 * Get the platform specific window id. This is equal to the hwnd on 
410 	 * Windows or the x11 window id on Linux.
411 	 *
412 	 * Bugs:
413 	 *     Unknown if this works on Mac OSX.
414 	 *
415 	 * Returns:
416 	 *     The platform specific window id.
417 	 */
418 	public @property size_t hwnd()
419 	{
420 		this._tk.eval("winfo id %s", this.id);
421 
422 		return this._tk.getResult!(string).chompPrefix("0x").to!(size_t)(16);
423 	}
424 
425 	/**
426 	 * Get the position of the cursor over the element. The cursor 
427 	 * position returned is relative to the screen. It is only returned if the 
428 	 * cursor is over the element.
429 	 *
430 	 * Returns:
431 	 *     An array holding the screen position of the cursor.
432 	 */
433 	public int[] getCursorPos()
434 	{
435 		this._tk.eval("winfo pointerxy %s", this.id);
436 
437 		return this._tk.getResult!(string).split().map!(to!(int)).array;
438 	}
439 
440 	/**
441 	 * Get the horizontal position of the cursor over the element. The cursor 
442 	 * position returned is relative to the screen. It is only returned if the 
443 	 * cursor is over the element.
444 	 *
445 	 * Returns:
446 	 *     The horizontal screen position of the cursor.
447 	 */
448 	public int getCursorXPos()
449 	{
450 		this._tk.eval("winfo pointerx %s", this.id);
451 
452 		return this._tk.getResult!(int);
453 	}
454 
455 	/**
456 	 * Get the vertical position of the cursor over the element. The cursor 
457 	 * position returned is relative to the screen. It is only returned if the 
458 	 * cursor is over the element.
459 	 *
460 	 * Returns:
461 	 *     The vertical screen position of the cursor.
462 	 */
463 	public int getCursorYPos()
464 	{
465 		this._tk.eval("winfo pointery %s", this.id);
466 
467 		return this._tk.getResult!(int);
468 	}
469 
470 	/**
471 	 * Get the width of the screen this element is displayed on.
472 	 *
473 	 * Returns:
474 	 *     The width of the screen.
475 	 */
476 	public int getScreenWidth()
477 	{
478 		this._tk.eval("winfo screenwidth %s", this.id);
479 
480 		return this._tk.getResult!(int);
481 	}
482 
483 	/**
484 	 * Get the height of the screen this element is displayed on.
485 	 *
486 	 * Returns:
487 	 *     The height of the screen.
488 	 */
489 	public int getScreenHeight()
490 	{
491 		this._tk.eval("winfo screenheight %s", this.id);
492 
493 		return this._tk.getResult!(int);
494 	}
495 
496 	/**
497 	 * Get the horizontal position of the element. The number returned is 
498 	 * calculated using the top, left-most pixel of the element including 
499 	 * border if one exists.
500 	 *
501 	 * Params:
502 	 *     relativeToParent = True to get the position relative to its parent, false for the position on the screen.
503 	 *
504 	 * Returns:
505 	 *     The horizontal position of the element.
506 	 */
507 	public int getXPos(bool relativeToParent = false)
508 	{
509 		if (relativeToParent)
510 		{
511 			this._tk.eval("winfo x %s", this.id);
512 		}
513 		else
514 		{
515 			this._tk.eval("winfo rootx %s", this.id);
516 		}
517 
518 		return this._tk.getResult!(int);
519 	}
520 
521 	/**
522 	 * Get the vertical position of the element. The number returned is 
523 	 * calculated using the top, left-most pixel of the element including 
524 	 * border if one exists.
525 	 *
526 	 * Params:
527 	 *     relativeToParent = True to get the position relative to its parent, false for the position on the screen.
528 	 *
529 	 * Returns:
530 	 *     The vertical position of the element.
531 	 */
532 	public int getYPos(bool relativeToParent = false)
533 	{
534 		if (relativeToParent)
535 		{
536 			this._tk.eval("winfo y %s", this.id);
537 		}
538 		else
539 		{
540 			this._tk.eval("winfo rooty %s", this.id);
541 		}
542 
543 		return this._tk.getResult!(int);
544 	}
545 
546 	/**
547 	 * Set if the element should change it size when requested to do so by a 
548 	 * geometry manager.
549 	 *
550 	 * Params:
551 	 *     enable = True to enable, false to disable.
552 	 *
553 	 * Returns:
554 	 *     This element to aid method chaining.
555 	 *
556 	 * See_Also:
557 	 *     $(LINK2 ../widget/widget.html#Widget.pack, tkd.widget.widget.Widget.pack) $(BR)
558 	 *     $(LINK2 ../widget/widget.html#Widget.grid, tkd.widget.widget.Widget.grid) $(BR)
559 	 */
560 	public auto enableGeometryAutoSize(this T)(bool enable)
561 	{
562 		this._tk.eval("pack propagate %s %s", this.id, enable);
563 		this._tk.eval("grid propagate %s %s", this.id, enable);
564 
565 		return cast(T) this;
566 	}
567 
568 	/**
569 	 * Used by the grid geometry manager. Sets options for grid columns that contain child widgets.
570 	 *
571 	 * Params:
572 	 *     index = The index of the column to configure.
573 	 *     weight = The weight of the column while expanding. The default is 1. 2 means expand twice as much, etc.
574 	 *     minSize = The min size of the column.
575 	 *     uniformGroup = The group to which the column will resize in uniform.
576 	 *     pad = Extra padding for the column.
577 	 *
578 	 * Returns:
579 	 *     This element to aid method chaining.
580 	 *
581 	 * See_Also:
582 	 *     $(LINK2 ../widget/widget.html#Widget.grid, tkd.widget.widget.Widget.grid) $(BR)
583 	 */
584 	public auto configureGeometryColumn(this T)(int index, int weight, int minSize = 0, int uniformGroup = 0, int pad = 0)
585 	{
586 		this._tk.eval("grid columnconfigure %s %s -weight %s -minsize %s -uniform %s -pad %s", this.id, index, weight, minSize, uniformGroup, pad);
587 
588 		return cast(T) this;
589 	}
590 
591 	/**
592 	 * Used by the grid geometry manager. Sets options for grid rows that contain child widgets.
593 	 *
594 	 * Params:
595 	 *     index = The index of the row to configure.
596 	 *     weight = The weight of the column while expanding. The default is 1. 2 means expand twice as much, etc.
597 	 *     minSize = The min size of the row.
598 	 *     uniformGroup = The group to which the row will resize in uniform.
599 	 *     pad = Extra padding for the row.
600 	 *
601 	 * Returns:
602 	 *     This element to aid method chaining.
603 	 *
604 	 * See_Also:
605 	 *     $(LINK2 ../widget/widget.html#Widget.grid, tkd.widget.widget.Widget.grid) $(BR)
606 	 */
607 	public auto configureGeometryRow(this T)(int index, int weight, int minSize = 0, int uniformGroup = 0, int pad = 0)
608 	{
609 		this._tk.eval("grid rowconfigure %s %s -weight %s -minsize %s -uniform %s -pad %s", this.id, index, weight, minSize, uniformGroup, pad);
610 
611 		return cast(T) this;
612 	}
613 
614 	/**
615 	 * Provides a simple means to block keyboard, button, and pointer events 
616 	 * from elements, while overriding the cursor with a configurable busy 
617 	 * cursor.
618 	 *
619 	 * Params:
620 	 *     busy = Specifies whether this element is busy or not.
621 	 *     cursor = The cursor to use if the element is busy.
622 	 *
623 	 * Returns:
624 	 *     This element to aid method chaining.
625 	 *
626 	 * Caveats:
627 	 *     Note that this method does not currently have any effect on 
628 	 *     MacOSX when Tk is built using Aqua support.
629 	 *
630 	 * See_Also:
631 	 *     $(LINK2 ./cursor.html, tkd.element.cursor) $(BR)
632 	 */
633 	public auto setBusy(this T)(bool busy, string cursor = Cursor.watch)
634 	{
635 		if (busy)
636 		{
637 			this._tk.eval("tk busy hold %s -cursor {%s}", this.id, cursor);
638 		}
639 		else
640 		{
641 			this._tk.eval("tk busy forget %s", this.id);
642 		}
643 
644 		return cast(T) this;
645 	}
646 
647 	/**
648 	 * Gets if the element is busy or not.
649 	 *
650 	 * Returns:
651 	 *     true if the element is busy, false if not.
652 	 *
653 	 * See_Also:
654 	 *     $(LINK2 ./cursor.html, tkd.element.cursor) $(BR)
655 	 */
656 	public bool isBusy(this T)()
657 	{
658 		this._tk.eval("tk busy status %s", this.id);
659 
660 		return this._tk.getResult!(int) == 1;
661 	}
662 
663 	/**
664 	 * Generates an event and arranges for it to be processed just as if it had 
665 	 * come from the operating system. Event provides a basic description of 
666 	 * the event, such as $(B &lt;Shift-Button-2&gt;) or $(B 
667 	 * &lt;&lt;Paste&gt;&gt;). The event argument may have any of the forms 
668 	 * allowed for the binding argument of the $(LINK2 
669 	 * ./uielement.html#UiElement.bind, bind) method except that it must 
670 	 * consist of a single event pattern only. Certain events, such as key 
671 	 * events, require that the window has focus to receive the event properly.
672 	 *
673 	 * Params:
674 	 *     event = The event to issue.
675 	 *
676 	 * See_Also:
677 	 *     $(LINK2 ../tkdapplication.html#TkdApplication.addVirtualEvent, tkd.tkdapplication.TkdApplication.addVirtualEvent) $(BR)
678 	 *     $(LINK2 ../tkdapplication.html#TkdApplication.deleteVirtualEvent, tkd.tkdapplication.TkdApplication.deleteVirtualEvent) $(BR)
679 	 *     $(LINK2 ./uielement.html#UiElement.bind, tkd.element.uielement.UiElement.bind) $(BR)
680 	 */
681 	public void generateEvent(this T)(string event)
682 	{
683 		assert(!std.regex.match(event, r"^<.*?>$").empty, "Event must take the form of <binding>");
684 
685 		this._tk.eval("event generate %s %s", this.id, event);
686 	}
687 
688 	/**
689 	 * Set the element to take focus so any key press or key release events for 
690 	 * the application are sent to that element. It is also possible to force 
691 	 * the operating system to apply focus to the element immediately.
692 	 *
693 	 * Params:
694 	 *     force = Whether or not to force the focus.
695 	 *
696 	 * Returns:
697 	 *     This element to aid method chaining.
698 	 */
699 	public auto focus(this T)(bool force = false)
700 	{
701 		if (force)
702 		{
703 			this._tk.eval("focus -force %s", this.id);
704 		}
705 		else
706 		{
707 			this._tk.eval("focus %s", this.id);
708 		}
709 
710 		return cast(T) this;
711 	}
712 
713 	/**
714 	 * This command implements simple pointer and keyboard grabs. When a grab 
715 	 * is set for a particular element, it restricts all pointer events to the 
716 	 * grab window and its descendants. Whenever the pointer is within the grab 
717 	 * element, the pointer will behave exactly the same as if there had been 
718 	 * no grab at all and all events will be reported in the normal fashion. 
719 	 * When the pointer is outside the element, button presses, releases and 
720 	 * mouse motion events are reported to the element, and element entry and 
721 	 * exit events are ignored. The grab 'owns' the pointer: elements outside 
722 	 * the grab will be visible on the screen but they will be insensitive 
723 	 * until the grab is released. The tree of elements underneath the grab 
724 	 * element can include windows, in which case all windows and their 
725 	 * descendants will continue to receive mouse events during the grab.
726 	 *
727 	 * Two forms of grabs are possible: local and global. A local grab affects 
728 	 * only the grabbing application: events will be reported to other 
729 	 * applications as if the grab had never occurred. Grabs are local by 
730 	 * default. A global grab locks out all applications on the screen, so that 
731 	 * only the given element and its descendants of the grabbing application 
732 	 * will be sensitive to pointer events (mouse button presses, mouse button 
733 	 * releases, pointer motions, entries, and exits). During global grabs the 
734 	 * window manager will not receive pointer events either.
735 	 *
736 	 * During local grabs, keyboard events (key presses and key releases) are 
737 	 * delivered as usual: the window manager controls which application 
738 	 * receives keyboard events, and if they are sent to any element in the 
739 	 * grabbing application then they are redirected to the focused element. 
740 	 * During a global grab all keyboard events are always sent to the grabbing 
741 	 * application. The focus command is still used to determine which element 
742 	 * in the application receives the keyboard events. The keyboard grab is 
743 	 * released when the grab is released.
744 	 *
745 	 * Params:
746 	 *     enable = Whether to enable or release the grab.
747 	 *     global = Whether or not the grab should be global.
748 	 *
749 	 * Returns:
750 	 *     This element to aid method chaining.
751 	 *
752 	 * Caveats:
753 	 *     It is very easy to use global grabs to render a display completely 
754 	 *     unusable (e.g. by setting a grab on an element which does not 
755 	 *     respond to events and not providing any mechanism for releasing the 
756 	 *     grab).  Take extreme care when using them! For a global grab to work 
757 	 *     the element needs to be placed and visible on the UI. Local grabs 
758 	 *     are not affected by this requirement.
759 	 */
760 	public auto setGrab(this T)(bool enable, bool global = false)
761 	{
762 		if (!enable)
763 		{
764 			this._tk.eval("grab release %s", this.id);
765 		}
766 		else if (global)
767 		{
768 			this._tk.eval("grab -global %s", this.id);
769 		}
770 		else
771 		{
772 			this._tk.eval("grab %s", this.id);
773 		}
774 
775 		return cast(T) this;
776 	}
777 
778 	/**
779 	 * Gets if the element is currently grabbing all events or not.
780 	 *
781 	 * Returns:
782 	 *     This element to aid method chaining.
783 	 */
784 	public bool isGrabbing(this T)()
785 	{
786 		this._tk.eval("grab status %s", this.id);
787 
788 		return this._tk.getResult!(string) != "none";
789 	}
790 
791 	/**
792 	 * Lower a window's position in the stacking order.
793 	 *
794 	 * Params:
795 	 *     element = The optional element to lower immedately beneath.
796 	 *
797 	 * Returns:
798 	 *     This element to aid method chaining.
799 	 */
800 	public auto lower(this T)(UiElement element = null)
801 	{
802 		if (element)
803 		{
804 			this._tk.eval("lower %s %s", this.id, element.id);
805 		}
806 		else
807 		{
808 			this._tk.eval("lower %s", this.id);
809 		}
810 
811 		return cast(T) this;
812 	}
813 
814 	/**
815 	 * Raise a window's position in the stacking order.
816 	 *
817 	 * Params:
818 	 *     element = The optional element to raise immedately above.
819 	 *
820 	 * Returns:
821 	 *     This element to aid method chaining.
822 	 */
823 	public auto raise(this T)(UiElement element = null)
824 	{
825 		if (element)
826 		{
827 			this._tk.eval("raise %s %s", this.id, element.id);
828 		}
829 		else
830 		{
831 			this._tk.eval("raise %s", this.id);
832 		}
833 
834 		return cast(T) this;
835 	}
836 }