1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 6 module dfl.base; 7 8 private import dfl.internal.dlib, dfl.internal.clib; 9 10 private import dfl.internal.winapi, dfl.drawing, dfl.event; 11 12 13 alias HWND HWindow; 14 15 16 17 interface IWindow { // docmain 18 19 @property HWindow handle(); // getter 20 } 21 22 alias IWindow IWin32Window; // deprecated 23 24 25 26 class DflException: Exception { // docmain 27 28 this(Dstring msg, string file = __FILE__, int line = __LINE__) { 29 super(msg, file, line); 30 } 31 } 32 33 34 35 alias DThrowable DflThrowable; 36 37 38 39 class StringObject: DObject { 40 41 Dstring value; 42 43 44 45 this(Dstring str) pure nothrow { 46 this.value = str; 47 } 48 49 50 override Dstring toString() { 51 return value; 52 } 53 54 55 override Dequ opEquals(Object o) { 56 return value == getObjectString(o); // ? 57 } 58 59 60 Dequ opEquals(StringObject s) { 61 return value == s.value; 62 } 63 64 65 override int opCmp(Object o) { 66 return stringICmp(value, getObjectString(o)); // ? 67 } 68 69 70 int opCmp(StringObject s) { 71 return stringICmp(value, s.value); 72 } 73 } 74 75 76 77 enum Keys: uint { // docmain 78 NONE = 0, /// No keys specified. 79 80 81 SHIFT = 0x10000, /// Modifier keys. 82 CONTROL = 0x20000, /// ditto 83 ALT = 0x40000, /// ditto 84 WINDOWS = 0x80000, /// ditto 85 86 A = 'A', /// Letters. 87 B = 'B', /// ditto 88 C = 'C', /// ditto 89 D = 'D', /// ditto 90 E = 'E', /// ditto 91 F = 'F', /// ditto 92 G = 'G', /// ditto 93 H = 'H', /// ditto 94 I = 'I', /// ditto 95 J = 'J', /// ditto 96 K = 'K', /// ditto 97 L = 'L', /// ditto 98 M = 'M', /// ditto 99 N = 'N', /// ditto 100 O = 'O', /// ditto 101 P = 'P', /// ditto 102 Q = 'Q', /// ditto 103 R = 'R', /// ditto 104 S = 'S', /// ditto 105 T = 'T', /// ditto 106 U = 'U', /// ditto 107 V = 'V', /// ditto 108 W = 'W', /// ditto 109 X = 'X', /// ditto 110 Y = 'Y', /// ditto 111 Z = 'Z', /// ditto 112 113 D0 = '0', /// Digits. 114 D1 = '1', /// ditto 115 D2 = '2', /// ditto 116 D3 = '3', /// ditto 117 D4 = '4', /// ditto 118 D5 = '5', /// ditto 119 D6 = '6', /// ditto 120 D7 = '7', /// ditto 121 D8 = '8', /// ditto 122 D9 = '9', /// ditto 123 124 F1 = 112, /// F - function keys. 125 F2 = 113, /// ditto 126 F3 = 114, /// ditto 127 F4 = 115, /// ditto 128 F5 = 116, /// ditto 129 F6 = 117, /// ditto 130 F7 = 118, /// ditto 131 F8 = 119, /// ditto 132 F9 = 120, /// ditto 133 F10 = 121, /// ditto 134 F11 = 122, /// ditto 135 F12 = 123, /// ditto 136 F13 = 124, /// ditto 137 F14 = 125, /// ditto 138 F15 = 126, /// ditto 139 F16 = 127, /// ditto 140 F17 = 128, /// ditto 141 F18 = 129, /// ditto 142 F19 = 130, /// ditto 143 F20 = 131, /// ditto 144 F21 = 132, /// ditto 145 F22 = 133, /// ditto 146 F23 = 134, /// ditto 147 F24 = 135, /// ditto 148 149 NUM_PAD0 = 96, /// Numbers on keypad. 150 NUM_PAD1 = 97, /// ditto 151 NUM_PAD2 = 98, /// ditto 152 NUM_PAD3 = 99, /// ditto 153 NUM_PAD4 = 100, /// ditto 154 NUM_PAD5 = 101, /// ditto 155 NUM_PAD6 = 102, /// ditto 156 NUM_PAD7 = 103, /// ditto 157 NUM_PAD8 = 104, /// ditto 158 NUM_PAD9 = 105, /// ditto 159 160 ADD = 107, /// 161 APPS = 93, /// Application. 162 ATTN = 246, /// 163 BACK = 8, /// Backspace. 164 CANCEL = 3, /// 165 CAPITAL = 20, /// 166 CAPS_LOCK = 20, /// ditto 167 CLEAR = 12, /// 168 CONTROL_KEY = 17, /// 169 CRSEL = 247, /// 170 DECIMAL = 110, /// 171 DEL = 46, /// 172 DELETE = DEL, /// 173 PERIOD = 190, /// 174 DOT = PERIOD, /// ditto 175 DIVIDE = 111, /// 176 DOWN = 40, /// Down arrow. 177 END = 35, /// 178 ENTER = 13, /// 179 ERASE_EOF = 249, /// 180 ESCAPE = 27, /// 181 EXECUTE = 43, /// 182 EXSEL = 248, /// 183 FINAL_MODE = 4, /// IME final mode. 184 HANGUL_MODE = 21, /// IME Hangul mode. 185 HANGUEL_MODE = 21, /// ditto 186 HANJA_MODE = 25, /// IME Hanja mode. 187 HELP = 47, /// 188 HOME = 36, /// 189 IME_ACCEPT = 30, /// 190 IME_CONVERT = 28, /// 191 IME_MODE_CHANGE = 31, /// 192 IME_NONCONVERT = 29, /// 193 INSERT = 45, /// 194 JUNJA_MODE = 23, /// 195 KANA_MODE = 21, /// 196 KANJI_MODE = 25, /// 197 LEFT_CONTROL = 162, /// Left Ctrl. 198 LEFT = 37, /// Left arrow. 199 LINE_FEED = 10, /// 200 LEFT_MENU = 164, /// Left Alt. 201 LEFT_SHIFT = 160, /// 202 LEFT_WIN = 91, /// Left Windows logo. 203 MENU = 18, /// Alt. 204 MULTIPLY = 106, /// 205 NEXT = 34, /// Page down. 206 NO_NAME = 252, // Reserved for future use. 207 NUM_LOCK = 144, /// 208 OEM8 = 223, // OEM specific. 209 OEM_CLEAR = 254, 210 PA1 = 253, 211 PAGE_DOWN = 34, /// 212 PAGE_UP = 33, /// 213 PAUSE = 19, /// 214 PLAY = 250, /// 215 PRINT = 42, /// 216 PRINT_SCREEN = 44, /// 217 PROCESS_KEY = 229, /// 218 RIGHT_CONTROL = 163, /// Right Ctrl. 219 RETURN = 13, /// 220 RIGHT = 39, /// Right arrow. 221 RIGHT_MENU = 165, /// Right Alt. 222 RIGHT_SHIFT = 161, /// 223 RIGHT_WIN = 92, /// Right Windows logo. 224 SCROLL = 145, /// Scroll lock. 225 SELECT = 41, /// 226 SEPARATOR = 108, /// 227 SHIFT_KEY = 16, /// 228 SNAPSHOT = 44, /// Print screen. 229 SPACE = 32, /// 230 SPACEBAR = SPACE, // Extra. 231 SUBTRACT = 109, /// 232 TAB = 9, /// 233 UP = 38, /// Up arrow. 234 ZOOM = 251, /// 235 236 // Windows 2000+ 237 BROWSER_BACK = 166, /// 238 BROWSER_FAVORITES = 171, /// ditto 239 BROWSER_FORWARD = 167, /// ditto 240 BROWSER_HOME = 172, /// ditto 241 BROWSER_REFRESH = 168, /// ditto 242 BROWSER_SEARCH = 170, /// ditto 243 BROWSER_STOP = 169, /// ditto 244 LAUNCH_APPLICATION1 = 182, /// 245 LAUNCH_APPLICATION2 = 183, /// ditto 246 LAUNCH_MAIL = 180, /// ditto 247 MEDIA_NEXT_TRACK = 176, /// 248 MEDIA_PLAY_PAUSE = 179, /// ditto 249 MEDIA_PREVIOUS_TRACK = 177, /// ditto 250 MEDIA_STOP = 178, /// ditto 251 OEM_BACKSLASH = 226, // OEM angle bracket or backslash. 252 OEM_CLOSE_BRACKETS = 221, 253 OEM_COMMA = 188, 254 OEM_MINUS = 189, 255 OEM_OPEN_BRACKETS = 219, 256 OEM_PERIOD = 190, 257 OEM_PIPE = 220, 258 OEM_PLUS = 187, 259 OEM_QUESTION = 191, 260 OEM_QUOTES = 222, 261 OEM_SEMICOLON = 186, 262 OEM_TILDE = 192, 263 SELECT_MEDIA = 181, /// 264 VOLUME_DOWN = 174, /// 265 VOLUME_MUTE = 173, /// ditto 266 VOLUME_UP = 175, /// ditto 267 268 /// Bit mask to extract key code from key value. 269 KEY_CODE = 0xFFFF, 270 271 /// Bit mask to extract modifiers from key value. 272 MODIFIERS = 0xFFFF0000, 273 } 274 275 276 277 enum MouseButtons: uint { // docmain 278 /// No mouse buttons specified. 279 NONE = 0, 280 281 LEFT = 0x100000, /// 282 RIGHT = 0x200000, /// ditto 283 MIDDLE = 0x400000, /// ditto 284 285 // Windows 2000+ 286 //XBUTTON1 = 0x800000, 287 //XBUTTON2 = 0x1000000, 288 } 289 290 291 292 enum CheckState: ubyte { 293 UNCHECKED = BST_UNCHECKED, /// 294 CHECKED = BST_CHECKED, /// ditto 295 INDETERMINATE = BST_INDETERMINATE, /// ditto 296 } 297 298 299 300 struct Message { // docmain 301 union { 302 struct { 303 HWND hWnd; /// 304 UINT msg; /// ditto 305 WPARAM wParam; /// ditto 306 LPARAM lParam; /// ditto 307 } 308 309 package MSG _winMsg; // .time and .pt are not always valid. 310 } 311 LRESULT result; /// 312 313 314 /// Construct a Message struct. 315 this(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) pure nothrow { 316 this.hWnd = hWnd; 317 this.msg = msg; 318 this.wParam = wParam; 319 this.lParam = lParam; 320 result = 0; 321 } 322 } 323 324 325 326 interface IMessageFilter { // docmain 327 328 // Return false to allow the message to be dispatched. 329 // Filter functions cannot modify messages. 330 bool preFilterMessage(ref Message m); 331 } 332 333 334 abstract class WaitHandle { 335 enum WAIT_TIMEOUT = dfl.internal.winapi.WAIT_TIMEOUT; // DMD 1.028: needs fqn, otherwise conflicts with std.thread 336 enum INVALID_HANDLE = .INVALID_HANDLE_VALUE; 337 338 339 this() { 340 h = INVALID_HANDLE; 341 } 342 343 344 // Used internally. 345 this(HANDLE h, bool owned = true) { 346 this.h = h; 347 this.owned = owned; 348 } 349 350 351 @property HANDLE handle() nothrow { // getter 352 return h; 353 } 354 355 356 @property void handle(HANDLE h) { // setter 357 this.h = h; 358 } 359 360 361 void close() { 362 CloseHandle(h); 363 h = INVALID_HANDLE; 364 } 365 366 367 ~this() { 368 if(owned) { 369 close(); 370 } 371 } 372 373 374 private static DWORD _wait(WaitHandle[] handles, BOOL waitall, DWORD msTimeout) { 375 DWORD result; 376 HANDLE* hs; 377 // Some implementations fail with > 64 handles, but that will return WAIT_FAILED; 378 // all implementations fail with >= 128 handles due to WAIT_ABANDONED_0 being 128. 379 if(handles.length >= 128) { 380 goto fail; 381 } 382 383 //hs = new HANDLE[handles.length]; 384 hs = cast(HANDLE*)alloca(HANDLE.sizeof * handles.length); 385 386 foreach(size_t i, WaitHandle wh; handles) { 387 hs[i] = wh.handle; 388 } 389 390 result = WaitForMultipleObjects(handles.length, hs, waitall, msTimeout); 391 if(WAIT_FAILED == result) { 392 fail: 393 throw new DflException("Wait failure"); 394 } 395 return result; 396 } 397 398 399 static void waitAll(WaitHandle[] handles) { 400 return waitAll(handles, INFINITE); 401 } 402 403 404 static void waitAll(WaitHandle[] handles, DWORD msTimeout) { 405 _wait(handles, true, msTimeout); 406 } 407 408 409 static int waitAny(WaitHandle[] handles) { 410 return waitAny(handles, INFINITE); 411 } 412 413 414 static int waitAny(WaitHandle[] handles, DWORD msTimeout) { 415 DWORD result; 416 result = _wait(handles, false, msTimeout); 417 return cast(int)result; // Same return info. 418 } 419 420 421 void waitOne() { 422 return waitOne(INFINITE); 423 } 424 425 426 void waitOne(DWORD msTimeout) { 427 DWORD result; 428 result = WaitForSingleObject(handle, msTimeout); 429 if(WAIT_FAILED == result) { 430 throw new DflException("Wait failure"); 431 } 432 } 433 434 435 private: 436 HANDLE h; 437 bool owned = true; 438 } 439 440 441 interface IAsyncResult { 442 @property WaitHandle asyncWaitHandle(); // getter 443 444 // Usually just returns false. 445 @property bool completedSynchronously(); // getter 446 447 // When true, it is safe to release its resources. 448 @property bool isCompleted(); // getter 449 } 450 451 452 /+ 453 class AsyncResult: IAsyncResult { 454 } 455 +/ 456 457 458 459 interface IButtonControl { // docmain 460 461 @property DialogResult dialogResult(); // getter 462 /// ditto 463 @property void dialogResult(DialogResult); // setter 464 465 466 void notifyDefault(bool); // True if default button. 467 468 469 void performClick(); // Raise click event. 470 } 471 472 473 474 enum DialogResult: ubyte { // docmain 475 NONE, /// 476 477 ABORT = IDABORT, /// 478 CANCEL = IDCANCEL, /// 479 IGNORE = IDIGNORE, /// 480 NO = IDNO, /// 481 OK = IDOK, /// 482 RETRY = IDRETRY, /// 483 YES = IDYES, /// 484 485 // Extra. 486 CLOSE = IDCLOSE, 487 HELP = IDHELP, 488 } 489 490 491 interface IDialogResult { 492 // /// 493 @property DialogResult dialogResult(); // getter 494 // /// ditto 495 @property void dialogResult(DialogResult); // setter 496 } 497 498 499 500 enum SortOrder: ubyte { 501 NONE, /// 502 503 ASCENDING, /// 504 DESCENDING, /// ditto 505 } 506 507 508 509 enum View: ubyte { 510 LARGE_ICON, /// 511 SMALL_ICON, /// 512 LIST, /// 513 DETAILS, /// 514 } 515 516 517 518 enum ItemBoundsPortion: ubyte { 519 ENTIRE, /// 520 ICON, /// 521 ITEM_ONLY, /// Excludes other stuff like check boxes. 522 LABEL, /// Item's text. 523 } 524 525 526 527 enum ItemActivation: ubyte { 528 STANDARD, /// 529 ONE_CLICK, /// 530 TWO_CLICK, /// 531 } 532 533 534 535 enum ColumnHeaderStyle: ubyte { 536 CLICKABLE, /// 537 NONCLICKABLE, /// 538 NONE, /// No column header. 539 } 540 541 542 543 enum BorderStyle: ubyte { 544 NONE, /// 545 546 FIXED_3D, /// 547 FIXED_SINGLE, /// ditto 548 } 549 550 551 552 enum FlatStyle: ubyte { 553 STANDARD, /// 554 FLAT, /// ditto 555 POPUP, /// ditto 556 SYSTEM, /// ditto 557 } 558 559 560 561 enum Appearance: ubyte { 562 NORMAL, /// 563 BUTTON, /// 564 } 565 566 567 568 enum ContentAlignment: ubyte { 569 TOP_LEFT, /// 570 BOTTOM_CENTER, /// 571 BOTTOM_LEFT, /// 572 BOTTOM_RIGHT, /// 573 MIDDLE_CENTER, /// 574 MIDDLE_LEFT, /// 575 MIDDLE_RIGHT, /// 576 TOP_CENTER, /// 577 TOP_RIGHT, /// 578 } 579 580 581 582 enum CharacterCasing: ubyte { 583 NORMAL, /// 584 LOWER, /// 585 UPPER, /// 586 } 587 588 589 590 // Not flags. 591 enum ScrollBars: ubyte { 592 NONE, /// 593 594 HORIZONTAL, /// 595 VERTICAL, /// ditto 596 BOTH, /// ditto 597 } 598 599 600 601 enum HorizontalAlignment: ubyte { 602 LEFT, /// 603 RIGHT, /// ditto 604 CENTER, /// ditto 605 } 606 607 608 609 enum DrawMode: ubyte { 610 NORMAL, /// 611 OWNER_DRAW_FIXED, /// 612 OWNER_DRAW_VARIABLE, /// ditto 613 } 614 615 616 617 enum DrawItemState: uint { 618 NONE = 0, /// 619 SELECTED = 1, /// ditto 620 DISABLED = 2, /// ditto 621 CHECKED = 8, /// ditto 622 FOCUS = 0x10, /// ditto 623 DEFAULT = 0x20, /// ditto 624 HOT_LIGHT = 0x40, /// ditto 625 NO_ACCELERATOR = 0x80, /// ditto 626 INACTIVE = 0x100, /// ditto 627 NO_FOCUS_RECT = 0x200, /// ditto 628 COMBO_BOX_EDIT = 0x1000, /// ditto 629 } 630 631 632 633 enum RightToLeft: ubyte { 634 INHERIT = 2, /// 635 YES = 1, /// ditto 636 NO = 0, /// ditto 637 } 638 639 640 641 enum ColorDepth: ubyte { 642 DEPTH_4BIT = 0x04, /// 643 DEPTH_8BIT = 0x08, /// ditto 644 DEPTH_16BIT = 0x10, /// ditto 645 DEPTH_24BIT = 0x18, /// ditto 646 DEPTH_32BIT = 0x20, /// ditto 647 } 648 649 650 651 class PaintEventArgs: EventArgs { 652 653 this(Graphics graphics, Rect clipRect) pure nothrow { 654 g = graphics; 655 cr = clipRect; 656 } 657 658 659 660 final @property Graphics graphics() pure nothrow { // getter 661 return g; 662 } 663 664 665 666 final @property Rect clipRectangle() pure nothrow { // getter 667 return cr; 668 } 669 670 671 private: 672 Graphics g; 673 Rect cr; 674 } 675 676 677 678 class CancelEventArgs: EventArgs { 679 680 // Initialize cancel to false. 681 this() pure nothrow { 682 cncl = false; 683 } 684 685 /// ditto 686 this(bool cancel) pure nothrow { 687 cncl = cancel; 688 } 689 690 691 692 final @property void cancel(bool byes) pure nothrow { // setter 693 cncl = byes; 694 } 695 696 /// ditto 697 final @property bool cancel() pure nothrow { // getter 698 return cncl; 699 } 700 701 702 private: 703 bool cncl; 704 } 705 706 707 class SizingEventArgs: EventArgs { 708 709 // Initialize cancel to false. 710 this(Size sz) pure nothrow { 711 _sz = sz; 712 } 713 714 715 @property Size size() pure nothrow { 716 return _sz; 717 } 718 719 /// ditto 720 @property void size(Size sz) pure nothrow { 721 _sz = sz; 722 } 723 724 725 @property void width(int w) pure nothrow { 726 _sz.width = w; 727 } 728 729 /// ditto 730 @property int width() pure nothrow { 731 return _sz.width; 732 } 733 734 735 @property void height(int h) pure nothrow { 736 _sz.height = h; 737 } 738 739 /// ditto 740 @property int height() pure nothrow { 741 return _sz.height; 742 } 743 744 745 private: 746 Size _sz; 747 } 748 749 750 class MovingEventArgs: EventArgs { 751 752 // Initialize cancel to false. 753 this(Point loc) pure nothrow { 754 _loc = loc; 755 } 756 757 758 @property Point location() pure nothrow { 759 return _loc; 760 } 761 762 /// ditto 763 @property void location(Point loc) pure nothrow { 764 _loc = loc; 765 } 766 767 768 @property void x(int posX) pure nothrow { 769 _loc.x = posX; 770 } 771 772 /// ditto 773 @property int x() pure nothrow { 774 return _loc.x; 775 } 776 777 778 @property void y(int posY) pure nothrow { 779 _loc.y = posY; 780 } 781 782 /// ditto 783 @property int y() pure nothrow { 784 return _loc.y; 785 } 786 787 788 private: 789 Point _loc; 790 } 791 792 793 class KeyEventArgs: EventArgs { 794 795 this(Keys keys) pure nothrow { 796 ks = keys; 797 } 798 799 800 801 final @property bool alt() pure nothrow { // getter 802 return (ks & Keys.ALT) != 0; 803 } 804 805 806 807 final @property bool control() pure nothrow { // getter 808 return (ks & Keys.CONTROL) != 0; 809 } 810 811 812 813 final @property void handled(bool byes) pure nothrow { // setter 814 hand = byes; 815 } 816 817 818 final @property bool handled() pure nothrow { // getter 819 return hand; 820 } 821 822 823 824 final @property Keys keyCode() pure nothrow { // getter 825 return ks & Keys.KEY_CODE; 826 } 827 828 829 830 final @property Keys keyData() pure nothrow { // getter 831 return ks; 832 } 833 834 835 836 // -keyData- as an int. 837 final @property int keyValue() pure nothrow { // getter 838 return cast(int)ks; 839 } 840 841 842 843 final @property Keys modifiers() pure nothrow { // getter 844 return ks & Keys.MODIFIERS; 845 } 846 847 848 849 final @property bool shift() pure nothrow { // getter 850 return (ks & Keys.SHIFT) != 0; 851 } 852 853 854 855 final @property bool windows() pure nothrow { // getter 856 return (ks & Keys.WINDOWS) != 0; 857 } 858 859 860 private: 861 Keys ks; 862 bool hand = false; 863 } 864 865 866 867 class KeyPressEventArgs: KeyEventArgs { 868 869 this(dchar ch) { 870 this(ch, (ch >= 'A' && ch <= 'Z') ? Keys.SHIFT : Keys.NONE); 871 } 872 873 /// ditto 874 this(dchar ch, Keys modifiers) 875 in { 876 assert((modifiers & Keys.MODIFIERS) == modifiers, "modifiers parameter can only contain modifiers"); 877 } 878 body { 879 _keych = ch; 880 881 int vk; 882 if(dfl.internal.utf.useUnicode) { 883 vk = 0xFF & VkKeyScanW(cast(WCHAR)ch); 884 } else 885 { vk = 0xFF & VkKeyScanA(cast(char)ch); } 886 887 super(cast(Keys)(vk | modifiers)); 888 } 889 890 891 892 final @property dchar keyChar() { // getter 893 return _keych; 894 } 895 896 897 private: 898 dchar _keych; 899 } 900 901 902 903 class MouseEventArgs: EventArgs { 904 905 // -delta- is mouse wheel rotations. 906 this(MouseButtons button, int clicks, int x, int y, int delta) pure nothrow { 907 btn = button; 908 clks = clicks; 909 _x = x; 910 _y = y; 911 dlt = delta; 912 } 913 914 915 916 final @property MouseButtons button() pure nothrow { // getter 917 return btn; 918 } 919 920 921 922 final @property int clicks() pure nothrow { // getter 923 return clks; 924 } 925 926 927 928 final @property int delta() pure nothrow { // getter 929 return dlt; 930 } 931 932 933 934 final @property int x() pure nothrow { // getter 935 return _x; 936 } 937 938 939 940 final @property int y() pure nothrow { // getter 941 return _y; 942 } 943 944 945 private: 946 MouseButtons btn; 947 int clks; 948 int _x, _y; 949 int dlt; 950 } 951 952 953 /+ 954 955 class LabelEditEventArgs: EventArgs { 956 957 this(int index) { 958 959 } 960 961 /// ditto 962 this(int index, Dstring labelText) { 963 this.idx = index; 964 this.ltxt = labelText; 965 } 966 967 968 969 final @property void cancelEdit(bool byes) { // setter 970 cancl = byes; 971 } 972 973 /// ditto 974 final @property bool cancelEdit() { // getter 975 return cancl; 976 } 977 978 979 980 // The text of the label's edit. 981 final @property Dstring label() { // getter 982 return ltxt; 983 } 984 985 986 987 // Gets the item's index. 988 final @property int item() { // getter 989 return idx; 990 } 991 992 993 private: 994 int idx; 995 Dstring ltxt; 996 bool cancl = false; 997 } 998 +/ 999 1000 1001 1002 class ColumnClickEventArgs: EventArgs { 1003 1004 this(int col) pure nothrow { 1005 this.col = col; 1006 } 1007 1008 1009 1010 final @property int column() pure nothrow { // getter 1011 return col; 1012 } 1013 1014 1015 private: 1016 int col; 1017 } 1018 1019 1020 1021 class DrawItemEventArgs: EventArgs { 1022 1023 this(Graphics g, Font f, Rect r, int i, DrawItemState dis) pure nothrow { 1024 this(g, f, r, i , dis, Color.empty, Color.empty); 1025 } 1026 1027 /// ditto 1028 this(Graphics g, Font f, Rect r, int i, DrawItemState dis, Color fc, Color bc) pure nothrow { 1029 gpx = g; 1030 fnt = f; 1031 rect = r; 1032 idx = i; 1033 distate = dis; 1034 fcolor = fc; 1035 bcolor = bc; 1036 } 1037 1038 1039 1040 final @property Color backColor() pure nothrow { // getter 1041 return bcolor; 1042 } 1043 1044 1045 1046 final @property Rect bounds() pure nothrow { // getter 1047 return rect; 1048 } 1049 1050 1051 1052 final @property Font font() pure nothrow { // getter 1053 return fnt; 1054 } 1055 1056 1057 1058 final @property Color foreColor() pure nothrow { // getter 1059 return fcolor; 1060 } 1061 1062 1063 1064 final @property Graphics graphics() pure nothrow { // getter 1065 return gpx; 1066 } 1067 1068 1069 1070 final @property int index() pure nothrow { // getter 1071 return idx; 1072 } 1073 1074 1075 1076 final @property DrawItemState state() pure nothrow { // getter 1077 return distate; 1078 } 1079 1080 1081 1082 void drawBackground() { 1083 /+ 1084 HBRUSH hbr; 1085 RECT _rect; 1086 1087 hbr = bcolor.createBrush(); 1088 try { 1089 rect.getRect(&_rect); 1090 FillRect(gpx.handle, &_rect, hbr); 1091 } 1092 finally { 1093 DeleteObject(hbr); 1094 } 1095 +/ 1096 1097 gpx.fillRectangle(bcolor, rect); 1098 } 1099 1100 1101 1102 void drawFocusRectangle() { 1103 if(distate & DrawItemState.FOCUS) { 1104 RECT _rect; 1105 rect.getRect(&_rect); 1106 DrawFocusRect(gpx.handle, &_rect); 1107 } 1108 } 1109 1110 1111 private: 1112 Graphics gpx; 1113 Font fnt; // Suggestion; the parent's font. 1114 Rect rect; 1115 int idx; 1116 DrawItemState distate; 1117 Color fcolor, bcolor; // Suggestion; depends on item state. 1118 } 1119 1120 1121 1122 class MeasureItemEventArgs: EventArgs { 1123 1124 this(Graphics g, int index, int itemHeight) { 1125 gpx = g; 1126 idx = index; 1127 iheight = itemHeight; 1128 } 1129 1130 /// ditto 1131 this(Graphics g, int index) { 1132 this(g, index, 0); 1133 } 1134 1135 1136 1137 final @property Graphics graphics() { // getter 1138 return gpx; 1139 } 1140 1141 1142 1143 final @property int index() { // getter 1144 return idx; 1145 } 1146 1147 1148 1149 final @property void itemHeight(int height) { // setter 1150 iheight = height; 1151 } 1152 1153 /// ditto 1154 final @property int itemHeight() { // getter 1155 return iheight; 1156 } 1157 1158 1159 1160 final @property void itemWidth(int width) { // setter 1161 iwidth = width; 1162 } 1163 1164 /// ditto 1165 final @property int itemWidth() { // getter 1166 return iwidth; 1167 } 1168 1169 1170 private: 1171 Graphics gpx; 1172 int idx, iheight, iwidth = 0; 1173 } 1174 1175 1176 1177 class Cursor { // docmain 1178 private static Cursor _cur; 1179 1180 1181 // Used internally. 1182 this(HCURSOR hcur, bool owned = true) { 1183 this.hcur = hcur; 1184 this.owned = owned; 1185 } 1186 1187 1188 ~this() { 1189 if(owned) { 1190 dispose(); 1191 } 1192 } 1193 1194 1195 1196 void dispose() { 1197 assert(owned); 1198 DestroyCursor(hcur); 1199 hcur = HCURSOR.init; 1200 } 1201 1202 1203 1204 static @property void current(Cursor cur) { // setter 1205 // Keep a reference so that it doesn't get garbage collected until set again. 1206 _cur = cur; 1207 1208 SetCursor(cur ? cur.hcur : HCURSOR.init); 1209 } 1210 1211 /// ditto 1212 static @property Cursor current() { // getter 1213 HCURSOR hcur = GetCursor(); 1214 return hcur ? new Cursor(hcur, false) : null; 1215 } 1216 1217 1218 1219 static @property void clip(Rect r) { // setter 1220 RECT rect; 1221 r.getRect(&rect); 1222 ClipCursor(&rect); 1223 } 1224 1225 /// ditto 1226 static @property Rect clip() { // getter 1227 RECT rect; 1228 GetClipCursor(&rect); 1229 return Rect(&rect); 1230 } 1231 1232 1233 1234 final @property HCURSOR handle() { // getter 1235 return hcur; 1236 } 1237 1238 1239 /+ 1240 // TODO: 1241 final @property Size size() { // getter 1242 Size result; 1243 ICONINFO iinfo; 1244 1245 if(GetIconInfo(hcur, &iinfo)) { 1246 1247 } 1248 1249 return result; 1250 } 1251 +/ 1252 1253 1254 1255 // Uses the actual size. 1256 final void draw(Graphics g, Point pt) { 1257 DrawIconEx(g.handle, pt.x, pt.y, hcur, 0, 0, 0, HBRUSH.init, DI_NORMAL); 1258 } 1259 1260 /+ 1261 /// ditto 1262 // Should not stretch if bigger, but should crop if smaller. 1263 final void draw(Graphics g, Rect r) { 1264 } 1265 +/ 1266 1267 1268 1269 final void drawStretched(Graphics g, Rect r) { 1270 // DrawIconEx operates differently if the width or height is zero 1271 // so bail out if zero and pretend the zero size cursor was drawn. 1272 int width = r.width; 1273 if(!width) { 1274 return; 1275 } 1276 int height = r.height; 1277 if(!height) { 1278 return; 1279 } 1280 1281 DrawIconEx(g.handle, r.x, r.y, hcur, width, height, 0, HBRUSH.init, DI_NORMAL); 1282 } 1283 1284 1285 override Dequ opEquals(Object o) { 1286 Cursor cur = cast(Cursor)o; 1287 if(!cur) { 1288 return 0; // Not equal. 1289 } 1290 return opEquals(cur); 1291 } 1292 1293 1294 Dequ opEquals(Cursor cur) { 1295 return hcur == cur.hcur; 1296 } 1297 1298 1299 /// Show/hide the current mouse cursor; reference counted. 1300 // show/hide are ref counted. 1301 static void hide() { 1302 ShowCursor(false); 1303 } 1304 1305 /// ditto 1306 // show/hide are ref counted. 1307 static void show() { 1308 ShowCursor(true); 1309 } 1310 1311 1312 /// The position of the current mouse cursor. 1313 static @property void position(Point pt) { // setter 1314 SetCursorPos(pt.x, pt.y); 1315 } 1316 1317 /// ditto 1318 static @property Point position() { // getter 1319 Point pt; 1320 GetCursorPos(&pt.point); 1321 return pt; 1322 } 1323 1324 1325 private: 1326 HCURSOR hcur; 1327 bool owned = true; 1328 } 1329 1330 1331 1332 class Cursors { // docmain 1333 private this() {} 1334 1335 1336 static: 1337 1338 1339 @property Cursor appStarting() { // getter 1340 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_APPSTARTING), false); 1341 } 1342 1343 1344 @property Cursor arrow() { // getter 1345 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false); 1346 } 1347 1348 1349 @property Cursor cross() { // getter 1350 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_CROSS), false); 1351 } 1352 1353 1354 //@property Cursor default() // getter 1355 @property Cursor defaultCursor() { // getter 1356 return arrow; 1357 } 1358 1359 1360 @property Cursor hand() { // getter 1361 version(SUPPORTS_HAND_CURSOR) { // Windows 98+ 1362 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_HAND), false); 1363 } 1364 else { 1365 static HCURSOR hcurHand; 1366 1367 if(!hcurHand) { 1368 hcurHand = LoadCursorA(HINSTANCE.init, IDC_HAND); 1369 if(!hcurHand) { // Must be Windows 95, so load the cursor from winhlp32.exe. 1370 UINT len; 1371 char[MAX_PATH] winhlppath = void; 1372 1373 len = GetWindowsDirectoryA(winhlppath.ptr, winhlppath.length - 16); 1374 if(!len || len > winhlppath.length - 16) { 1375 load_failed: 1376 return arrow; // Just fall back to a normal arrow. 1377 } 1378 strcpy(winhlppath.ptr + len, "\\winhlp32.exe"); 1379 1380 HINSTANCE hinstWinhlp; 1381 hinstWinhlp = LoadLibraryExA(winhlppath.ptr, HANDLE.init, LOAD_LIBRARY_AS_DATAFILE); 1382 if(!hinstWinhlp) { 1383 goto load_failed; 1384 } 1385 1386 HCURSOR hcur; 1387 hcur = LoadCursorA(hinstWinhlp, cast(char*)106); 1388 if(!hcur) { // No such cursor resource. 1389 FreeLibrary(hinstWinhlp); 1390 goto load_failed; 1391 } 1392 hcurHand = CopyCursor(hcur); 1393 if(!hcurHand) { 1394 FreeLibrary(hinstWinhlp); 1395 //throw new DflException("Unable to copy cursor resource"); 1396 goto load_failed; 1397 } 1398 1399 FreeLibrary(hinstWinhlp); 1400 } 1401 } 1402 1403 assert(hcurHand); 1404 // Copy the cursor and own it here so that it's safe to dispose it. 1405 return new Cursor(CopyCursor(hcurHand)); 1406 } 1407 } 1408 1409 1410 @property Cursor help() { // getter 1411 HCURSOR hcur; 1412 hcur = LoadCursorA(HINSTANCE.init, IDC_HELP); 1413 if(!hcur) { // IDC_HELP might not be supported on Windows 95, so fall back to a normal arrow. 1414 return arrow; 1415 } 1416 return new Cursor(hcur); 1417 } 1418 1419 1420 @property Cursor hSplit() { // getter 1421 // ... 1422 return sizeNS; 1423 } 1424 1425 /// ditto 1426 @property Cursor vSplit() { // getter 1427 // ... 1428 return sizeWE; 1429 } 1430 1431 1432 1433 @property Cursor iBeam() { // getter 1434 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_IBEAM), false); 1435 } 1436 1437 1438 @property Cursor no() { // getter 1439 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_NO), false); 1440 } 1441 1442 1443 1444 @property Cursor sizeAll() { // getter 1445 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZEALL), false); 1446 } 1447 1448 /// ditto 1449 @property Cursor sizeNESW() { // getter 1450 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZENESW), false); 1451 } 1452 1453 /// ditto 1454 @property Cursor sizeNS() { // getter 1455 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZENS), false); 1456 } 1457 1458 /// ditto 1459 @property Cursor sizeNWSE() { // getter 1460 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZENWSE), false); 1461 } 1462 1463 /// ditto 1464 @property Cursor sizeWE() { // getter 1465 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZEWE), false); 1466 } 1467 1468 1469 /+ 1470 1471 // Insertion point. 1472 @property Cursor upArrow() { // getter 1473 // ... 1474 } 1475 +/ 1476 1477 1478 @property Cursor waitCursor() { // getter 1479 return new Cursor(LoadCursorA(HINSTANCE.init, IDC_WAIT), false); 1480 } 1481 } 1482