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