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 <Alt>, The Alt key.) 140 * $(PARAM_ROW <Button1> $(BR) <B1>, Mouse button one.) 141 * $(PARAM_ROW <Button2> $(BR) <B2>, Mouse button two.) 142 * $(PARAM_ROW <Button3> $(BR) <B3>, Mouse button three.) 143 * $(PARAM_ROW <Button3> $(BR) <B5>, Mouse button five.) 144 * $(PARAM_ROW <Button4> $(BR) <B4>, Mouse button four.) 145 * $(PARAM_ROW <Control>, The Ctrl key.) 146 * $(PARAM_ROW <Double>, Modifier for doing something twice.) 147 * $(PARAM_ROW <Extended>, Extended keyboard support.) 148 * $(PARAM_ROW <Lock>, Unknown.) 149 * $(PARAM_ROW <Meta> $(BR) <M>, The meta key.) 150 * $(PARAM_ROW <Mod1> $(BR) <M1> $(BR) <Command>, First modifier key.) 151 * $(PARAM_ROW <Mod2> $(BR) <M2> $(BR) <Option>, Second modifier key.) 152 * $(PARAM_ROW <Mod3> $(BR) <M3>, Third modifier key.) 153 * $(PARAM_ROW <Mod4> $(BR) <M4>, Fourth modifier key.) 154 * $(PARAM_ROW <Mod5> $(BR) <M5>, Fifth modifier key.) 155 * $(PARAM_ROW <Quadruple>, Modifier for doing something four times.) 156 * $(PARAM_ROW <Shift>, The Shift key.) 157 * $(PARAM_ROW <Triple>, 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 <Control-Button-1>) will match the 168 * event, but $(B <Mod1-Button-1>) 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 <Double-Button-1>) 186 * is equivalent to $(B <Button-1><Button-1>) 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 <Activate> $(BR) <Deactivate>, 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 <MouseWheel>, 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 <KeyPress> $(BR) <KeyRelease>, 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 <ButtonPress> $(BR) <ButtonRelease> $(BR) <Motion>, 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 <Configure>, 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 <Map> $(BR) <Unmap>, 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 <Visibility>, 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 <Expose>, 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 <Destroy>, 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 <FocusIn> $(BR) <FocusOut>, 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 <Enter> $(BR) <Leave>, 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 <Property>, 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 <Colormap>, 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 <CirculateRequest> $(BR) <ConfigureRequest> $(BR) <Create> $(BR) <MapRequest> $(BR) <ResizeRequest>, 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 <Circulate> $(BR) <Gravity> $(BR) <Reparent>, 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 <1>) is equivalent to $(B <ButtonPress-1>). 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 <Control-comma>) is 248 * equivalent to $(B <Control-KeyPress-comma>). 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 <<AltUnderlined>>, 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 <<Invoke>>, This can be sent to some widgets (e.g. button, listbox, menu) as an alternative to <space>.) 256 * $(PARAM_ROW <<ListboxSelect>>, This is sent to a listbox when the set of selected item(s) in the listbox is updated.) 257 * $(PARAM_ROW <<MenuSelect>>, 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 <<Modified>>, This is sent to a text widget when the contents of the widget are changed.) 259 * $(PARAM_ROW <<Selection>>, This is sent to a text widget when the selection in the widget is changed.) 260 * $(PARAM_ROW <<ThemeChanged>>, This is sent to a text widget when the ttk (Tile) theme changed.) 261 * $(PARAM_ROW <<TraverseIn>>, This is sent to a widget when the focus enters the widget because of a user-driven “tab to widget” action.) 262 * $(PARAM_ROW <<TraverseOut>>, 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 <<Clear>>, Delete the currently selected widget contents.) 269 * $(PARAM_ROW <<Copy>>, Copy the currently selected widget contents to the clipboard.) 270 * $(PARAM_ROW <<Cut>>, Move the currently selected widget contents to the clipboard.) 271 * $(PARAM_ROW <<LineEnd>>, Move to the end of the line in the current widget while deselecting any selected contents.) 272 * $(PARAM_ROW <<LineStart>>, Move to the start of the line in the current widget while deselecting any selected contents.) 273 * $(PARAM_ROW <<NextChar>>, Move to the next item (i.e., visible character) in the current widget while deselecting any selected contents.) 274 * $(PARAM_ROW <<NextLine>>, Move to the next line in the current widget while deselecting any selected contents.) 275 * $(PARAM_ROW <<NextPara>>, Move to the next paragraph in the current widget while deselecting any selected contents.) 276 * $(PARAM_ROW <<NextWord>>, Move to the next group of items (i.e., visible word) in the current widget while deselecting any selected contents.) 277 * $(PARAM_ROW <<Paste>>, Replace the currently selected widget contents with the contents of the clipboard.) 278 * $(PARAM_ROW <<PasteSelection>>, Insert the contents of the selection at the mouse location. (This event has meaningful %x and %y substitutions).) 279 * $(PARAM_ROW <<PrevChar>>, Move to the previous item (i.e., visible character) in the current widget while deselecting any selected contents.) 280 * $(PARAM_ROW <<PrevLine>>, Move to the previous line in the current widget while deselecting any selected contents.) 281 * $(PARAM_ROW <<PrevPara>>, Move to the previous paragraph in the current widget while deselecting any selected contents.) 282 * $(PARAM_ROW <<PrevWindow>>, Traverse to the previous window.) 283 * $(PARAM_ROW <<PrevWord>>, Move to the previous group of items (i.e., visible word) in the current widget while deselecting any selected contents.) 284 * $(PARAM_ROW <<Redo>>, Redo one undone action.) 285 * $(PARAM_ROW <<SelectAll>>, Set the range of selected contents to the complete widget.) 286 * $(PARAM_ROW <<SelectLineEnd>>, Move to the end of the line in the current widget while extending the range of selected contents.) 287 * $(PARAM_ROW <<SelectLineStart>>, Move to the start of the line in the current widget while extending the range of selected contents.) 288 * $(PARAM_ROW <<SelectNextChar>>, Move to the next item (i.e., visible character) in the current widget while extending the range of selected contents.) 289 * $(PARAM_ROW <<SelectNextLine>>, Move to the next line in the current widget while extending the range of selected contents.) 290 * $(PARAM_ROW <<SelectNextPara>>, Move to the next paragraph in the current widget while extending the range of selected contents.) 291 * $(PARAM_ROW <<SelectNextWord>>, 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 <<SelectNone>>, Reset the range of selected contents to be empty.) 293 * $(PARAM_ROW <<SelectPrevChar>>, Move to the previous item (i.e., visible character) in the current widget while extending the range of selected contents.) 294 * $(PARAM_ROW <<SelectPrevLine>>, Move to the previous line in the current widget while extending the range of selected contents.) 295 * $(PARAM_ROW <<SelectPrevPara>>, Move to the previous paragraph in the current widget while extending the range of selected contents.) 296 * $(PARAM_ROW <<SelectPrevWord>>, 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 <<ToggleSelection>>, Toggle the selection.) 298 * $(PARAM_ROW <<Undo>>, 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 <Shift-Button-2>) or $(B 667 * <<Paste>>). 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 }