1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 /// 6 module dfl.control; 7 8 private import dfl.internal.dlib, dfl.internal.clib; 9 10 private import dfl.base, dfl.form, dfl.drawing; 11 private import dfl.internal.winapi, dfl.application, dfl.event, dfl.label; 12 private import dfl.internal.wincom, dfl.internal.utf, dfl.collections, dfl.internal.com; 13 private import core.memory; 14 15 version(NO_DRAG_DROP) 16 version = DFL_NO_DRAG_DROP; 17 18 version(DFL_NO_DRAG_DROP) 19 { 20 } 21 else 22 { 23 private import dfl.data; 24 } 25 26 version(DFL_NO_MENUS) 27 { 28 } 29 else 30 { 31 private import dfl.menu; 32 } 33 34 //version = RADIO_GROUP_LAYOUT; 35 version = DFL_NO_ZOMBIE_FORM; 36 37 38 /// 39 enum AnchorStyles: ubyte 40 { 41 NONE = 0, /// 42 TOP = 1, /// ditto 43 BOTTOM = 2, /// ditto 44 LEFT = 4, /// ditto 45 RIGHT = 8, /// ditto 46 47 /+ 48 // Extras: 49 VERTICAL = TOP | BOTTOM, 50 HORIZONTAL = LEFT | RIGHT, 51 ALL = TOP | BOTTOM | LEFT | RIGHT, 52 DEFAULT = TOP | LEFT, 53 TOP_LEFT = TOP | LEFT, 54 TOP_RIGHT = TOP | RIGHT, 55 BOTTOM_LEFT = BOTTOM | LEFT, 56 BOTTOM_RIGHT = BOTTOM | RIGHT, 57 +/ 58 } 59 60 61 /// Flags for setting control bounds. 62 enum BoundsSpecified: ubyte 63 { 64 NONE = 0, /// 65 X = 1, /// ditto 66 Y = 2, /// ditto 67 LOCATION = 1 | 2, /// ditto 68 WIDTH = 4, /// ditto 69 HEIGHT = 8, /// ditto 70 SIZE = 4 | 8, /// ditto 71 ALL = 1 | 2 | 4 | 8, /// ditto 72 } 73 74 75 /// Layout docking style. 76 enum DockStyle: ubyte 77 { 78 NONE, /// 79 BOTTOM, /// 80 FILL, /// 81 LEFT, /// 82 RIGHT, /// 83 TOP, /// 84 } 85 86 87 private 88 { 89 struct GetZIndex 90 { 91 Control find; 92 int index = -1; 93 private int _tmp = 0; 94 } 95 96 97 extern(Windows) BOOL getZIndexCallback(HWND hwnd, LPARAM lparam) 98 { 99 GetZIndex* gzi = cast(GetZIndex*)lparam; 100 if(hwnd == gzi.find.hwnd) 101 { 102 gzi.index = gzi._tmp; 103 return FALSE; // Stop, found it. 104 } 105 106 Control ctrl; 107 ctrl = Control.fromHandle(hwnd); 108 if(ctrl && ctrl.parent is gzi.find.parent) 109 { 110 gzi._tmp++; 111 } 112 113 return TRUE; // Keep looking. 114 } 115 } 116 117 118 /// Effect flags for drag/drop operations. 119 enum DragDropEffects: DWORD 120 { 121 NONE = 0, /// 122 COPY = 1, /// ditto 123 MOVE = 2, /// ditto 124 LINK = 4, /// ditto 125 SCROLL = 0x80000000, /// ditto 126 ALL = COPY | MOVE | LINK | SCROLL, /// ditto 127 } 128 129 130 /// Drag/drop action. 131 enum DragAction: HRESULT 132 { 133 CONTINUE = S_OK, /// 134 CANCEL = DRAGDROP_S_CANCEL, /// ditto 135 DROP = DRAGDROP_S_DROP, /// ditto 136 } 137 138 139 // Flags. 140 deprecated enum UICues: uint 141 { 142 NONE = 0, 143 SHOW_FOCUS = 1, 144 SHOW_KEYBOARD = 2, 145 SHOWN = SHOW_FOCUS | SHOW_KEYBOARD, 146 CHANGE_FOCUS = 4, 147 CHANGE_KEYBOARD = 8, // Key mnemonic underline cues are on. 148 CHANGED = CHANGE_FOCUS | CHANGE_KEYBOARD, 149 } 150 151 152 // May be OR'ed together. 153 /// Style flags of a control. 154 enum ControlStyles: uint 155 { 156 NONE = 0, /// 157 158 CONTAINER_CONTROL = 0x1, /// ditto 159 160 // TODO: implement. 161 USER_PAINT = 0x2, /// ditto 162 163 OPAQUE = 0x4, /// ditto 164 RESIZE_REDRAW = 0x10, /// ditto 165 //FIXED_WIDTH = 0x20, // TODO: implement. 166 //FIXED_HEIGHT = 0x40, // TODO: implement. 167 STANDARD_CLICK = 0x100, /// ditto 168 SELECTABLE = 0x200, /// ditto 169 170 // TODO: implement. 171 USER_MOUSE = 0x400, /// ditto 172 173 //SUPPORTS_TRANSPARENT_BACK_COLOR = 0x800, // Only if USER_PAINT and parent is derived from Control. TODO: implement. 174 STANDARD_DOUBLE_CLICK = 0x1000, /// ditto 175 ALL_PAINTING_IN_WM_PAINT = 0x2000, /// ditto 176 CACHE_TEXT = 0x4000, /// ditto 177 ENABLE_NOTIFY_MESSAGE = 0x8000, // deprecated. Calls onNotifyMessage() for every message. 178 //DOUBLE_BUFFER = 0x10000, // TODO: implement. 179 180 WANT_TAB_KEY = 0x01000000, 181 WANT_ALL_KEYS = 0x02000000, 182 } 183 184 185 /// Control creation parameters. 186 struct CreateParams 187 { 188 Dstring className; /// 189 Dstring caption; /// ditto 190 void* param; /// ditto 191 HWND parent; /// ditto 192 HMENU menu; /// ditto 193 HINSTANCE inst; /// ditto 194 int x; /// ditto 195 int y; /// ditto 196 int width; /// ditto 197 int height; /// ditto 198 DWORD classStyle; /// ditto 199 DWORD exStyle; /// ditto 200 DWORD style; /// ditto 201 } 202 203 204 deprecated class UICuesEventArgs: EventArgs 205 { 206 deprecated: 207 208 this(UICues uic) 209 { 210 chg = uic; 211 } 212 213 214 final UICues changed() // getter 215 { 216 return chg; 217 } 218 219 220 final bool changeFocus() 221 { 222 return (chg & UICues.CHANGE_FOCUS) != 0; 223 } 224 225 226 final bool changeKeyboard() 227 { 228 return (chg & UICues.CHANGE_KEYBOARD) != 0; 229 } 230 231 232 final bool showFocus() 233 { 234 return (chg & UICues.SHOW_FOCUS) != 0; 235 } 236 237 238 final bool showKeyboard() 239 { 240 return (chg & UICues.SHOW_KEYBOARD) != 0; 241 } 242 243 244 private: 245 UICues chg; 246 } 247 248 249 /// 250 class ControlEventArgs: EventArgs 251 { 252 /// 253 this(Control ctrl) 254 { 255 this.ctrl = ctrl; 256 } 257 258 259 /// 260 final @property Control control() // getter 261 { 262 return ctrl; 263 } 264 265 266 private: 267 Control ctrl; 268 } 269 270 271 /// 272 class HelpEventArgs: EventArgs 273 { 274 /// 275 this(Point mousePos) 276 { 277 mpos = mousePos; 278 } 279 280 281 /// 282 final @property void handled(bool byes) // setter 283 { 284 hand = byes; 285 } 286 287 /// ditto 288 final @property bool handled() // getter 289 { 290 return hand; 291 } 292 293 294 /// 295 final @property Point mousePos() // getter 296 { 297 return mpos; 298 } 299 300 301 private: 302 Point mpos; 303 bool hand = false; 304 } 305 306 307 /// 308 class InvalidateEventArgs: EventArgs 309 { 310 /// 311 this(Rect invalidRect) 312 { 313 ir = invalidRect; 314 } 315 316 317 /// 318 final @property Rect invalidRect() // getter 319 { 320 return ir; 321 } 322 323 324 private: 325 Rect ir; 326 } 327 328 329 // /// 330 // New dimensions before resizing. 331 deprecated class BeforeResizeEventArgs: EventArgs 332 { 333 deprecated: 334 335 /// 336 this(int width, int height) 337 { 338 this.w = width; 339 this.h = height; 340 } 341 342 343 /// 344 void width(int cx) // setter 345 { 346 w = cx; 347 } 348 349 /// ditto 350 int width() // getter 351 { 352 return w; 353 } 354 355 356 /// 357 void height(int cy) // setter 358 { 359 h = cy; 360 } 361 362 /// ditto 363 int height() // getter 364 { 365 return h; 366 } 367 368 369 private: 370 int w, h; 371 } 372 373 374 /// 375 class LayoutEventArgs: EventArgs 376 { 377 /// 378 this(Control affectedControl) 379 { 380 ac = affectedControl; 381 } 382 383 384 /// 385 final @property Control affectedControl() // getter 386 { 387 return ac; 388 } 389 390 391 private: 392 Control ac; 393 } 394 395 396 version(DFL_NO_DRAG_DROP) {} else 397 { 398 /// 399 class DragEventArgs: EventArgs 400 { 401 /// 402 this(dfl.data.IDataObject dataObj, int keyState, int x, int y, 403 DragDropEffects allowedEffect, DragDropEffects effect) 404 { 405 _dobj = dataObj; 406 _keyState = keyState; 407 _x = x; 408 _y = y; 409 _allowedEffect = allowedEffect; 410 _effect = effect; 411 } 412 413 414 /// 415 final @property DragDropEffects allowedEffect() // getter 416 { 417 return _allowedEffect; 418 } 419 420 421 /// 422 final @property void effect(DragDropEffects newEffect) // setter 423 { 424 _effect = newEffect; 425 } 426 427 428 /// ditto 429 final @property DragDropEffects effect() // getter 430 { 431 return _effect; 432 } 433 434 435 /// 436 final @property dfl.data.IDataObject data() // getter 437 { 438 return _dobj; 439 } 440 441 442 /// 443 // State of ctrl, alt, shift, and mouse buttons. 444 final @property int keyState() // getter 445 { 446 return _keyState; 447 } 448 449 450 /// 451 final @property int x() // getter 452 { 453 return _x; 454 } 455 456 457 /// 458 final @property int y() // getter 459 { 460 return _y; 461 } 462 463 464 private: 465 dfl.data.IDataObject _dobj; 466 int _keyState; 467 int _x, _y; 468 DragDropEffects _allowedEffect, _effect; 469 } 470 471 472 /// 473 class GiveFeedbackEventArgs: EventArgs 474 { 475 /// 476 this(DragDropEffects effect, bool useDefaultCursors) 477 { 478 _effect = effect; 479 udefcurs = useDefaultCursors; 480 } 481 482 483 /// 484 final @property DragDropEffects effect() // getter 485 { 486 return _effect; 487 } 488 489 490 /// 491 final @property void useDefaultCursors(bool byes) // setter 492 { 493 udefcurs = byes; 494 } 495 496 /// ditto 497 final @property bool useDefaultCursors() // getter 498 { 499 return udefcurs; 500 } 501 502 503 private: 504 DragDropEffects _effect; 505 bool udefcurs; 506 } 507 508 509 /// 510 class QueryContinueDragEventArgs: EventArgs 511 { 512 /// 513 this(int keyState, bool escapePressed, DragAction action) 514 { 515 _keyState = keyState; 516 escp = escapePressed; 517 _action = action; 518 } 519 520 521 /// 522 final @property void action(DragAction newAction) // setter 523 { 524 _action = newAction; 525 } 526 527 /// ditto 528 final @property DragAction action() // getter 529 { 530 return _action; 531 } 532 533 534 /// 535 final @property bool escapePressed() // getter 536 { 537 return escp; 538 } 539 540 541 /// 542 // State of ctrl, alt and shift. 543 final @property int keyState() // getter 544 { 545 return _keyState; 546 } 547 548 549 private: 550 int _keyState; 551 bool escp; 552 DragAction _action; 553 } 554 } 555 556 557 version(NO_WINDOWS_HUNG_WORKAROUND) 558 { 559 } 560 else 561 { 562 version = WINDOWS_HUNG_WORKAROUND; 563 } 564 debug 565 { 566 version=_DFL_WINDOWS_HUNG_WORKAROUND; 567 } 568 version(WINDOWS_HUNG_WORKAROUND) 569 { 570 version=_DFL_WINDOWS_HUNG_WORKAROUND; 571 } 572 573 version(_DFL_WINDOWS_HUNG_WORKAROUND) 574 { 575 class WindowsHungDflException: DflException 576 { 577 this(Dstring msg) 578 { 579 super(msg); 580 } 581 } 582 } 583 584 alias BOOL delegate(HWND) EnumWindowsCallback; 585 package struct EnumWindowsCallbackData 586 { 587 EnumWindowsCallback callback; 588 DThrowable exception; 589 } 590 591 592 // Callback for EnumWindows() and EnumChildWindows(). 593 private extern(Windows) BOOL enumingWindows(HWND hwnd, LPARAM lparam) nothrow 594 { 595 auto cbd = *(cast(EnumWindowsCallbackData*)lparam); 596 try 597 { 598 return cbd.callback(hwnd); 599 } 600 catch (DThrowable e) 601 { 602 cbd.exception = e; 603 return FALSE; 604 } 605 assert(0); 606 } 607 608 609 private struct Efi 610 { 611 HWND hwParent; 612 EnumWindowsCallbackData cbd; 613 } 614 615 616 // Callback for EnumChildWindows(). -lparam- = pointer to Efi; 617 private extern(Windows) BOOL enumingFirstWindows(HWND hwnd, LPARAM lparam) nothrow 618 { 619 auto efi = cast(Efi*)lparam; 620 if(efi.hwParent == GetParent(hwnd)) 621 { 622 try 623 { 624 return efi.cbd.callback(hwnd); 625 } 626 catch (DThrowable e) 627 { 628 efi.cbd.exception = e; 629 return FALSE; 630 } 631 } 632 return TRUE; 633 } 634 635 636 package BOOL enumWindows(EnumWindowsCallback dg) 637 { 638 EnumWindowsCallbackData cbd; 639 cbd.callback = dg; 640 scope (exit) if (cbd.exception) throw cbd.exception; 641 static assert((&cbd).sizeof <= LPARAM.sizeof); 642 return EnumWindows(&enumingWindows, cast(LPARAM)&cbd); 643 } 644 645 646 package BOOL enumChildWindows(HWND hwParent, EnumWindowsCallback dg) 647 { 648 EnumWindowsCallbackData cbd; 649 cbd.callback = dg; 650 scope (exit) if (cbd.exception) throw cbd.exception; 651 static assert((&cbd).sizeof <= LPARAM.sizeof); 652 return EnumChildWindows(hwParent, &enumingWindows, cast(LPARAM)&cbd); 653 } 654 655 656 // Only the parent's children, not its children. 657 package BOOL enumFirstChildWindows(HWND hwParent, EnumWindowsCallback dg) 658 { 659 Efi efi; 660 efi.hwParent = hwParent; 661 efi.cbd.callback = dg; 662 scope (exit) if (efi.cbd.exception) throw efi.cbd.exception; 663 return EnumChildWindows(hwParent, &enumingFirstWindows, cast(LPARAM)&efi); 664 } 665 666 667 /// 668 enum ControlFont: ubyte 669 { 670 COMPATIBLE, /// 671 OLD, /// ditto 672 NATIVE, /// ditto 673 } 674 675 676 debug 677 { 678 import std.string; 679 } 680 681 682 /// Control class. 683 class Control: DObject, IWindow // docmain 684 { 685 /// 686 static class ControlCollection 687 { 688 protected this(Control owner) 689 { 690 _owner = owner; 691 } 692 693 694 deprecated alias length count; 695 696 /// 697 @property int length() // getter 698 { 699 if(_owner.isHandleCreated) 700 { 701 // Inefficient :( 702 uint len = 0; 703 foreach(Control ctrl; this) 704 { 705 len++; 706 } 707 return len; 708 } 709 else 710 { 711 return children.length; 712 } 713 } 714 715 716 /// 717 @property Control opIndex(int i) // getter 718 { 719 if(_owner.isHandleCreated) 720 { 721 int oni = 0; 722 foreach(Control ctrl; this) 723 { 724 if(oni == i) 725 return ctrl; 726 oni++; 727 } 728 // Index out of bounds, bad things happen. 729 assert(0); 730 } 731 else 732 { 733 return children[i]; 734 } 735 } 736 737 738 /// 739 void add(Control ctrl) 740 { 741 ctrl.parent = _owner; 742 } 743 744 745 /// 746 // opIn ? 747 bool contains(Control ctrl) 748 { 749 return indexOf(ctrl) != -1; 750 } 751 752 753 /// 754 int indexOf(Control ctrl) 755 { 756 if(_owner.isHandleCreated) 757 { 758 int i = 0; 759 int foundi = -1; 760 761 762 BOOL enuming(HWND hwnd) 763 { 764 if(hwnd == ctrl.handle) 765 { 766 foundi = i; 767 return false; // Stop. 768 } 769 770 i++; 771 return true; // Continue. 772 } 773 774 775 enumFirstChildWindows(_owner.handle, &enuming); 776 return foundi; 777 } 778 else 779 { 780 foreach(int i, Control onCtrl; children) 781 { 782 if(onCtrl == ctrl) 783 return i; 784 } 785 return -1; 786 } 787 } 788 789 790 /// 791 void remove(Control ctrl) 792 { 793 if(_owner.isHandleCreated) 794 { 795 _removeCreated(ctrl.handle); 796 } 797 else 798 { 799 int i = indexOf(ctrl); 800 if(i != -1) 801 _removeNotCreated(i); 802 } 803 } 804 805 806 private void _removeCreated(HWND hwnd) 807 { 808 DestroyWindow(hwnd); // ? 809 } 810 811 812 package void _removeNotCreated(int i) 813 { 814 if(!i) 815 children = children[1 .. children.length]; 816 else if(i == children.length - 1) 817 children = children[0 .. i]; 818 else 819 children = children[0 .. i] ~ children[i + 1 .. children.length]; 820 } 821 822 823 /// 824 void removeAt(int i) 825 { 826 if(_owner.isHandleCreated) 827 { 828 int ith = 0; 829 HWND hwndith; 830 831 832 BOOL enuming(HWND hwnd) 833 { 834 if(ith == i) 835 { 836 hwndith = hwnd; 837 return false; // Stop. 838 } 839 840 ith++; 841 return true; // Continue. 842 } 843 844 845 enumFirstChildWindows(_owner.handle, &enuming); 846 if(hwndith) 847 _removeCreated(hwndith); 848 } 849 else 850 { 851 _removeNotCreated(i); 852 } 853 } 854 855 856 protected final @property Control owner() // getter 857 { 858 return _owner; 859 } 860 861 862 /// 863 int opApply(int delegate(ref Control) dg) 864 { 865 int result = 0; 866 867 if(_owner.isHandleCreated) 868 { 869 BOOL enuming(HWND hwnd) 870 { 871 Control ctrl = fromHandle(hwnd); 872 if(ctrl) 873 { 874 result = dg(ctrl); 875 if(result) 876 return false; // Stop. 877 } 878 879 return true; // Continue. 880 } 881 882 883 enumFirstChildWindows(_owner.handle, &enuming); 884 } 885 else 886 { 887 foreach(Control ctrl; children) 888 { 889 result = dg(ctrl); 890 if(result) 891 break; 892 } 893 } 894 895 return result; 896 } 897 898 mixin OpApplyAddIndex!(opApply, Control); 899 900 901 package: 902 Control _owner; 903 Control[] children; // Only valid if -owner- isn't created yet (or is recreating). 904 905 906 /+ 907 final void _array_swap(int ifrom, int ito) 908 { 909 if(ifrom == ito || 910 ifrom < 0 || ito < 0 || 911 ifrom >= length || ito >= length) 912 return; 913 914 Control cto; 915 cto = children[ito]; 916 children[ito] = children[ifrom]; 917 children[ifrom] = cto; 918 } 919 +/ 920 921 922 final void _simple_front_one(int i) 923 { 924 if(i < 0 || i >= length - 1) 925 return; 926 927 children = children[0 .. i] ~ children[i + 1 .. i + 2] ~ children[i .. i + 1] ~ children[i + 2 .. children.length]; 928 } 929 930 931 final void _simple_front_one(Control c) 932 { 933 return _simple_front_one(indexOf(c)); 934 } 935 936 937 final void _simple_back_one(int i) 938 { 939 if(i <= 0 || i >= length) 940 return; 941 942 children = children[0 .. i - 1] ~ children[i + 1 .. i + 2] ~ children[i .. i + 1] ~ children[i + 2 .. children.length]; 943 } 944 945 946 final void _simple_back_one(Control c) 947 { 948 return _simple_back_one(indexOf(c)); 949 } 950 951 952 final void _simple_back(int i) 953 { 954 if(i <= 0 || i >= length) 955 return; 956 957 children = children[i .. i + 1] ~ children[0 .. i] ~ children[i + 1 .. children.length]; 958 } 959 960 961 final void _simple_back(Control c) 962 { 963 return _simple_back(indexOf(c)); 964 } 965 966 967 final void _simple_front(int i) 968 { 969 if(i < 0 || i >= length - 1) 970 return; 971 972 children = children[0 .. i] ~ children[i + 1 .. children.length] ~ children[i .. i + 1]; 973 } 974 975 976 final void _simple_front(Control c) 977 { 978 return _simple_front(indexOf(c)); 979 } 980 } 981 982 983 private void _ctrladded(ControlEventArgs cea) 984 { 985 if(Application._compat & DflCompat.CONTROL_PARENT_096) 986 { 987 if(!(_exStyle() & WS_EX_CONTROLPARENT)) 988 { 989 if(!(cbits & CBits.FORM)) 990 { 991 //if((cea.control._style() & WS_TABSTOP) || (cea.control._exStyle() & WS_EX_CONTROLPARENT)) 992 _exStyle(_exStyle() | WS_EX_CONTROLPARENT); 993 } 994 } 995 } 996 else 997 { 998 assert(getStyle(ControlStyles.CONTAINER_CONTROL), "Control added to non-container parent"); 999 } 1000 1001 onControlAdded(cea); 1002 } 1003 1004 1005 private void _ctrlremoved(ControlEventArgs cea) 1006 { 1007 alayout(cea.control); 1008 1009 onControlRemoved(cea); 1010 } 1011 1012 1013 /// 1014 protected void onControlAdded(ControlEventArgs cea) 1015 { 1016 controlAdded(this, cea); 1017 } 1018 1019 1020 /// 1021 protected void onControlRemoved(ControlEventArgs cea) 1022 { 1023 controlRemoved(this, cea); 1024 } 1025 1026 1027 /// 1028 @property final HWindow handle() // IWindow getter 1029 { 1030 if(!isHandleCreated) 1031 { 1032 debug(APP_PRINT) 1033 cprintf("Control created due to handle request.\n"); 1034 1035 createHandle(); 1036 } 1037 1038 return hwnd; 1039 } 1040 1041 1042 version(DFL_NO_DRAG_DROP) {} else 1043 { 1044 /// 1045 @property void allowDrop(bool byes) // setter 1046 { 1047 /+ 1048 if(dyes) 1049 _exStyle(_exStyle() | WS_EX_ACCEPTFILES); 1050 else 1051 _exStyle(_exStyle() & ~WS_EX_ACCEPTFILES); 1052 +/ 1053 1054 if(byes) 1055 { 1056 if(!droptarget) 1057 { 1058 droptarget = new DropTarget(this); 1059 if(isHandleCreated) 1060 { 1061 switch(RegisterDragDrop(hwnd, droptarget)) 1062 { 1063 case S_OK: 1064 case DRAGDROP_E_ALREADYREGISTERED: // Hmm. 1065 break; 1066 1067 default: 1068 droptarget = null; 1069 throw new DflException("Unable to register drag-drop"); 1070 } 1071 } 1072 } 1073 } 1074 else 1075 { 1076 delete droptarget; 1077 droptarget = null; 1078 RevokeDragDrop(hwnd); 1079 } 1080 } 1081 1082 /// ditto 1083 @property bool allowDrop() // getter 1084 { 1085 /+ 1086 return (_exStyle() & WS_EX_ACCEPTFILES) != 0; 1087 +/ 1088 1089 return droptarget !is null; 1090 } 1091 } 1092 1093 1094 /+ 1095 deprecated void anchor(AnchorStyles a) // setter 1096 { 1097 /+ 1098 anch = a; 1099 if(!(anch & (AnchorStyles.LEFT | AnchorStyles.RIGHT))) 1100 anch |= AnchorStyles.LEFT; 1101 if(!(anch & (AnchorStyles.TOP | AnchorStyles.BOTTOM))) 1102 anch |= AnchorStyles.TOP; 1103 +/ 1104 1105 sdock = DockStyle.NONE; // Can't be set at the same time. 1106 } 1107 1108 1109 deprecated AnchorStyles anchor() // getter 1110 { 1111 //return anch; 1112 return cast(AnchorStyles)(AnchorStyles.LEFT | AnchorStyles.TOP); 1113 } 1114 +/ 1115 1116 1117 private void _propagateBackColorAmbience() 1118 { 1119 Color bc; 1120 bc = backColor; 1121 1122 1123 void pa(Control pc) 1124 { 1125 foreach(Control ctrl; pc.ccollection) 1126 { 1127 if(Color.empty == ctrl.backc) // If default. 1128 { 1129 if(bc == ctrl.backColor) // If same default. 1130 { 1131 ctrl.deleteThisBackgroundBrush(); // Needs to be recreated with new color. 1132 ctrl.onBackColorChanged(EventArgs.empty); 1133 1134 pa(ctrl); // Recursive. 1135 } 1136 } 1137 } 1138 } 1139 1140 1141 pa(this); 1142 } 1143 1144 1145 /// 1146 protected void onBackColorChanged(EventArgs ea) 1147 { 1148 debug(EVENT_PRINT) 1149 { 1150 cprintf("{ Event: onBackColorChanged - Control %.*s }\n", name); 1151 } 1152 1153 backColorChanged(this, ea); 1154 } 1155 1156 1157 /// 1158 @property void backColor(Color c) // setter 1159 { 1160 if(backc == c) 1161 return; 1162 1163 deleteThisBackgroundBrush(); // Needs to be recreated with new color. 1164 backc = c; 1165 onBackColorChanged(EventArgs.empty); 1166 1167 _propagateBackColorAmbience(); 1168 if(isHandleCreated) 1169 invalidate(true); // Redraw! 1170 } 1171 1172 /// ditto 1173 @property Color backColor() // getter 1174 { 1175 if(Color.empty == backc) 1176 { 1177 if(parent) 1178 { 1179 return parent.backColor; 1180 } 1181 return defaultBackColor; 1182 } 1183 return backc; 1184 } 1185 1186 1187 /// 1188 final @property int bottom() // getter 1189 { 1190 return wrect.bottom; 1191 } 1192 1193 1194 /// 1195 final @property void bounds(Rect r) // setter 1196 { 1197 setBoundsCore(r.x, r.y, r.width, r.height, BoundsSpecified.ALL); 1198 } 1199 1200 /// ditto 1201 final @property Rect bounds() // getter 1202 { 1203 return wrect; 1204 } 1205 1206 1207 /+ 1208 final @property Rect originalBounds() // getter package 1209 { 1210 return oldwrect; 1211 } 1212 +/ 1213 1214 1215 /// 1216 protected void setBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) 1217 { 1218 // Make sure at least one flag is set. 1219 //if(!(specified & BoundsSpecified.ALL)) 1220 if(!specified) 1221 return; 1222 1223 if(isHandleCreated) 1224 { 1225 UINT swpf = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE; 1226 1227 if(specified & BoundsSpecified.X) 1228 { 1229 if(!(specified & BoundsSpecified.Y)) 1230 y = this.top(); 1231 swpf &= ~SWP_NOMOVE; 1232 } 1233 else if(specified & BoundsSpecified.Y) 1234 { 1235 x = this.left(); 1236 swpf &= ~SWP_NOMOVE; 1237 } 1238 1239 if(specified & BoundsSpecified.WIDTH) 1240 { 1241 if(!(specified & BoundsSpecified.HEIGHT)) 1242 height = this.height(); 1243 swpf &= ~SWP_NOSIZE; 1244 } 1245 else if(specified & BoundsSpecified.HEIGHT) 1246 { 1247 width = this.width(); 1248 swpf &= ~SWP_NOSIZE; 1249 } 1250 1251 SetWindowPos(hwnd, HWND.init, x, y, width, height, swpf); 1252 // Window events will update -wrect-. 1253 } 1254 else 1255 { 1256 if(specified & BoundsSpecified.X) 1257 wrect.x = x; 1258 if(specified & BoundsSpecified.Y) 1259 wrect.y = y; 1260 if(specified & BoundsSpecified.WIDTH) 1261 { 1262 if(width < 0) 1263 width = 0; 1264 1265 wrect.width = width; 1266 wclientsz.width = width; 1267 } 1268 if(specified & BoundsSpecified.HEIGHT) 1269 { 1270 if(height < 0) 1271 height = 0; 1272 1273 wrect.height = height; 1274 wclientsz.height = height; 1275 } 1276 1277 //oldwrect = wrect; 1278 } 1279 } 1280 1281 1282 /// 1283 final @property bool canFocus() // getter 1284 { 1285 /+ 1286 LONG wl = _style(); 1287 return /+ hwnd && +/ (wl & WS_VISIBLE) && !(wl & WS_DISABLED); 1288 +/ 1289 //return visible && enabled; 1290 // Don't need to check -isHandleCreated- because IsWindowVisible() will fail from a null HWND. 1291 return /+ isHandleCreated && +/ IsWindowVisible(hwnd) && IsWindowEnabled(hwnd); 1292 } 1293 1294 1295 /// 1296 final @property bool canSelect() // getter 1297 out(result) 1298 { 1299 if(result) 1300 { 1301 assert(isHandleCreated); 1302 } 1303 } 1304 body 1305 { 1306 // All parent controls need to be visible and enabled, too. 1307 // Don't need to check -isHandleCreated- because IsWindowVisible() will fail from a null HWND. 1308 return /+ isHandleCreated && +/ (ctrlStyle & ControlStyles.SELECTABLE) && 1309 IsWindowVisible(hwnd) && IsWindowEnabled(hwnd); 1310 } 1311 1312 1313 package final bool _hasSelStyle() 1314 { 1315 return getStyle(ControlStyles.SELECTABLE); 1316 } 1317 1318 1319 /// 1320 // Returns true if this control has the mouse capture. 1321 final @property bool capture() // getter 1322 { 1323 return isHandleCreated && hwnd == GetCapture(); 1324 } 1325 1326 /// ditto 1327 final @property void capture(bool cyes) // setter 1328 { 1329 if(cyes) 1330 SetCapture(hwnd); 1331 else 1332 ReleaseCapture(); 1333 } 1334 1335 1336 // When true, validating and validated events are fired when the control 1337 // receives focus. Typically set to false for controls such as a Help button. 1338 // Default is true. 1339 deprecated final bool causesValidation() // getter 1340 { 1341 //return cvalidation; 1342 return false; 1343 } 1344 1345 1346 deprecated protected void onCausesValidationChanged(EventArgs ea) 1347 { 1348 //causesValidationChanged(this, ea); 1349 } 1350 1351 1352 deprecated final void causesValidation(bool vyes) // setter 1353 { 1354 /+ 1355 if(cvalidation == vyes) 1356 return; 1357 1358 cvalidation = vyes; 1359 1360 onCausesValidationChanged(EventArgs.empty); 1361 +/ 1362 } 1363 1364 1365 /// 1366 final @property Rect clientRectangle() // getter 1367 { 1368 return Rect(Point(0, 0), wclientsz); 1369 } 1370 1371 1372 /// 1373 final bool contains(Control ctrl) 1374 { 1375 //return ccollection.contains(ctrl); 1376 return ctrl && ctrl.parent is this; 1377 } 1378 1379 1380 /// 1381 final @property Size clientSize() // getter 1382 { 1383 return wclientsz; 1384 } 1385 1386 /// ditto 1387 final @property void clientSize(Size sz) // setter 1388 { 1389 setClientSizeCore(sz.width, sz.height); 1390 } 1391 1392 1393 /// 1394 protected void setClientSizeCore(int width, int height) 1395 { 1396 /+ 1397 if(isHandleCreated) 1398 setBoundsCore(0, 0, width, height, BoundsSpecified.SIZE); 1399 1400 //wclientsz = Size(width, height); 1401 +/ 1402 1403 RECT r; 1404 1405 r.left = 0; 1406 r.top = 0; 1407 r.right = width; 1408 r.bottom = height; 1409 1410 AdjustWindowRectEx(&r, _style(), FALSE, _exStyle()); 1411 1412 setBoundsCore(0, 0, r.right - r.left, r.bottom - r.top, BoundsSpecified.SIZE); 1413 } 1414 1415 1416 /// 1417 // This window or one of its children has focus. 1418 final @property bool containsFocus() // getter 1419 { 1420 if(!isHandleCreated) 1421 return false; 1422 1423 HWND hwfocus = GetFocus(); 1424 return hwfocus == hwnd || IsChild(hwnd, hwfocus); 1425 } 1426 1427 1428 version(DFL_NO_MENUS) 1429 { 1430 } 1431 else 1432 { 1433 /// 1434 protected void onContextMenuChanged(EventArgs ea) 1435 { 1436 contextMenuChanged(this, ea); 1437 } 1438 1439 1440 /// 1441 @property void contextMenu(ContextMenu menu) // setter 1442 { 1443 if(cmenu is menu) 1444 return; 1445 1446 cmenu = menu; 1447 1448 if(isHandleCreated) 1449 { 1450 onContextMenuChanged(EventArgs.empty); 1451 } 1452 } 1453 1454 /// ditto 1455 @property ContextMenu contextMenu() // getter 1456 { 1457 return cmenu; 1458 } 1459 } 1460 1461 1462 /// 1463 final @property ControlCollection controls() // getter 1464 { 1465 //return new ControlCollection(this); 1466 return ccollection; 1467 } 1468 1469 1470 /// 1471 final @property bool created() // getter 1472 { 1473 // To-do: only return true when createHandle finishes. 1474 // Will also need to update uses of created/isHandleCreated. 1475 // Return false again when disposing/killing. 1476 //return isHandleCreated; 1477 return isHandleCreated || recreatingHandle; 1478 } 1479 1480 1481 private void _propagateCursorAmbience() 1482 { 1483 Cursor cur; 1484 cur = cursor; 1485 1486 1487 void pa(Control pc) 1488 { 1489 foreach(Control ctrl; pc.ccollection) 1490 { 1491 if(ctrl.wcurs is null) // If default. 1492 { 1493 if(cur is ctrl.cursor) // If same default. 1494 { 1495 ctrl.onCursorChanged(EventArgs.empty); 1496 1497 pa(ctrl); // Recursive. 1498 } 1499 } 1500 } 1501 } 1502 1503 1504 pa(this); 1505 } 1506 1507 1508 /// 1509 protected void onCursorChanged(EventArgs ea) 1510 { 1511 /+ 1512 debug(EVENT_PRINT) 1513 { 1514 cprintf("{ Event: onCursorChanged - Control %.*s }\n", name); 1515 } 1516 +/ 1517 1518 if(isHandleCreated) 1519 { 1520 if(visible && enabled) 1521 { 1522 Point curpt = Cursor.position; 1523 if(hwnd == WindowFromPoint(curpt.point)) 1524 { 1525 SendMessageA(hwnd, WM_SETCURSOR, cast(WPARAM)hwnd, 1526 MAKELPARAM( 1527 SendMessageA(hwnd, WM_NCHITTEST, 0, MAKELPARAM(curpt.x, curpt.y)), 1528 WM_MOUSEMOVE) 1529 ); 1530 } 1531 } 1532 } 1533 1534 cursorChanged(this, ea); 1535 } 1536 1537 1538 /// 1539 @property void cursor(Cursor cur) // setter 1540 { 1541 if(cur is wcurs) 1542 return; 1543 1544 wcurs = cur; 1545 onCursorChanged(EventArgs.empty); 1546 1547 _propagateCursorAmbience(); 1548 } 1549 1550 /// ditto 1551 @property Cursor cursor() // getter 1552 { 1553 if(!wcurs) 1554 { 1555 if(parent) 1556 { 1557 return parent.cursor; 1558 } 1559 return _defaultCursor; 1560 } 1561 return wcurs; 1562 } 1563 1564 1565 /// 1566 static @property Color defaultBackColor() // getter 1567 { 1568 return Color.systemColor(COLOR_BTNFACE); 1569 } 1570 1571 1572 /// 1573 static @property Color defaultForeColor() //getter 1574 { 1575 return Color.systemColor(COLOR_BTNTEXT); 1576 } 1577 1578 1579 private static Font _deffont = null; 1580 1581 1582 private static Font _createOldFont() 1583 { 1584 return new Font(cast(HFONT)GetStockObject(DEFAULT_GUI_FONT), false); 1585 } 1586 1587 1588 private static Font _createCompatibleFont() 1589 { 1590 Font result; 1591 result = _createOldFont(); 1592 1593 try 1594 { 1595 OSVERSIONINFOA osi; 1596 osi.dwOSVersionInfoSize = osi.sizeof; 1597 if(GetVersionExA(&osi) && osi.dwMajorVersion >= 5) 1598 { 1599 // "MS Shell Dlg" / "MS Shell Dlg 2" not always supported. 1600 result = new Font("MS Shell Dlg 2", result.getSize(GraphicsUnit.POINT), GraphicsUnit.POINT); 1601 } 1602 } 1603 catch 1604 { 1605 } 1606 1607 //if(!result) 1608 // result = _createOldFont(); 1609 assert(result !is null); 1610 1611 return result; 1612 } 1613 1614 1615 private static Font _createNativeFont() 1616 { 1617 Font result; 1618 1619 NONCLIENTMETRICSA ncm; 1620 ncm.cbSize = ncm.sizeof; 1621 if(!SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, ncm.sizeof, &ncm, 0)) 1622 { 1623 result = _createCompatibleFont(); 1624 } 1625 else 1626 { 1627 result = new Font(&ncm.lfMessageFont, true); 1628 } 1629 1630 return result; 1631 } 1632 1633 1634 private static void _setDeffont(ControlFont cf) 1635 { 1636 synchronized 1637 { 1638 assert(_deffont is null); 1639 switch(cf) 1640 { 1641 case ControlFont.COMPATIBLE: 1642 _deffont = _createCompatibleFont(); 1643 break; 1644 case ControlFont.NATIVE: 1645 _deffont = _createNativeFont(); 1646 break; 1647 case ControlFont.OLD: 1648 _deffont = _createOldFont(); 1649 break; 1650 default: 1651 assert(0); 1652 } 1653 } 1654 } 1655 1656 1657 deprecated alias defaultFont controlFont; 1658 1659 /// 1660 static @property void defaultFont(ControlFont cf) // setter 1661 { 1662 if(_deffont) 1663 throw new DflException("Control font already selected"); 1664 _setDeffont(cf); 1665 } 1666 1667 /// ditto 1668 static @property void defaultFont(Font f) // setter 1669 { 1670 if(_deffont) 1671 throw new DflException("Control font already selected"); 1672 _deffont = f; 1673 } 1674 1675 /// ditto 1676 static @property Font defaultFont() // getter 1677 { 1678 if(!_deffont) 1679 { 1680 _setDeffont(ControlFont.COMPATIBLE); 1681 } 1682 1683 return _deffont; 1684 } 1685 1686 1687 package static class SafeCursor: Cursor 1688 { 1689 this(HCURSOR hcur) 1690 { 1691 super(hcur, false); 1692 } 1693 1694 1695 override void dispose() 1696 { 1697 } 1698 1699 1700 /+ 1701 ~this() 1702 { 1703 super.dispose(); 1704 } 1705 +/ 1706 } 1707 1708 1709 package static @property Cursor _defaultCursor() // getter 1710 { 1711 static Cursor def = null; 1712 1713 if(!def) 1714 { 1715 synchronized 1716 { 1717 if(!def) 1718 def = new SafeCursor(LoadCursorA(HINSTANCE.init, IDC_ARROW)); 1719 } 1720 } 1721 1722 return def; 1723 } 1724 1725 1726 /// 1727 @property Rect displayRectangle() // getter 1728 { 1729 return clientRectangle; 1730 } 1731 1732 1733 /// 1734 //protected void onDockChanged(EventArgs ea) 1735 protected void onHasLayoutChanged(EventArgs ea) 1736 { 1737 if(parent) 1738 parent.alayout(this); 1739 1740 //dockChanged(this, ea); 1741 hasLayoutChanged(this, ea); 1742 } 1743 1744 alias onHasLayoutChanged onDockChanged; 1745 1746 1747 private final void _alreadyLayout() 1748 { 1749 throw new DflException("Control already has a layout"); 1750 } 1751 1752 1753 /// 1754 @property DockStyle dock() // getter 1755 { 1756 return sdock; 1757 } 1758 1759 /// ditto 1760 @property void dock(DockStyle ds) // setter 1761 { 1762 if(ds == sdock) 1763 return; 1764 1765 DockStyle _olddock = sdock; 1766 sdock = ds; 1767 /+ 1768 anch = AnchorStyles.NONE; // Can't be set at the same time. 1769 +/ 1770 1771 if(DockStyle.NONE == ds) 1772 { 1773 if(DockStyle.NONE != _olddock) // If it was even docking before; don't unset hasLayout for something else. 1774 hasLayout = false; 1775 } 1776 else 1777 { 1778 // Ensure not replacing some other layout, but OK if replacing another dock. 1779 if(DockStyle.NONE == _olddock) 1780 { 1781 if(hasLayout) 1782 _alreadyLayout(); 1783 } 1784 hasLayout = true; 1785 } 1786 1787 /+ // Called by hasLayout. 1788 if(isHandleCreated) 1789 { 1790 onDockChanged(EventArgs.empty); 1791 } 1792 +/ 1793 } 1794 1795 1796 /// Get or set whether or not this control currently has its bounds managed. Fires onHasLayoutChanged as needed. 1797 final @property bool hasLayout() // getter 1798 { 1799 if(cbits & CBits.HAS_LAYOUT) 1800 return true; 1801 return false; 1802 } 1803 1804 /// ditto 1805 final @property void hasLayout(bool byes) // setter 1806 { 1807 //if(byes == hasLayout) 1808 // return; // No! setting this property again must trigger onHasLayoutChanged again. 1809 1810 if(byes) 1811 cbits |= CBits.HAS_LAYOUT; 1812 else 1813 cbits &= ~CBits.HAS_LAYOUT; 1814 1815 if(byes) // No need if layout is removed. 1816 { 1817 if(isHandleCreated) 1818 { 1819 onHasLayoutChanged(EventArgs.empty); 1820 } 1821 } 1822 } 1823 1824 1825 package final void _venabled(bool byes) 1826 { 1827 if(isHandleCreated) 1828 { 1829 EnableWindow(hwnd, byes); 1830 // Window events will update -wstyle-. 1831 } 1832 else 1833 { 1834 if(byes) 1835 wstyle &= ~WS_DISABLED; 1836 else 1837 wstyle |= WS_DISABLED; 1838 } 1839 } 1840 1841 1842 /// 1843 final @property void enabled(bool byes) // setter 1844 { 1845 if(byes) 1846 cbits |= CBits.ENABLED; 1847 else 1848 cbits &= ~CBits.ENABLED; 1849 1850 /+ 1851 if(!byes) 1852 { 1853 _venabled(false); 1854 } 1855 else 1856 { 1857 if(!parent || parent.enabled) 1858 _venabled(true); 1859 } 1860 1861 _propagateEnabledAmbience(); 1862 +/ 1863 1864 _venabled(byes); 1865 } 1866 1867 /// 1868 final @property bool enabled() // getter 1869 { 1870 /* 1871 return IsWindowEnabled(hwnd) ? true : false; 1872 */ 1873 1874 return (wstyle & WS_DISABLED) == 0; 1875 } 1876 1877 1878 private void _propagateEnabledAmbience() 1879 { 1880 /+ // Isn't working... 1881 if(cbits & CBits.FORM) 1882 return; 1883 1884 bool en = enabled; 1885 1886 void pa(Control pc) 1887 { 1888 foreach(Control ctrl; pc.ccollection) 1889 { 1890 if(ctrl.cbits & CBits.ENABLED) 1891 { 1892 _venabled(en); 1893 1894 pa(ctrl); 1895 } 1896 } 1897 } 1898 1899 pa(this); 1900 +/ 1901 } 1902 1903 1904 /// 1905 final void enable() 1906 { 1907 enabled = true; 1908 } 1909 1910 /// ditto 1911 final void disable() 1912 { 1913 enabled = false; 1914 } 1915 1916 1917 /// 1918 @property bool focused() // getter 1919 { 1920 //return isHandleCreated && hwnd == GetFocus(); 1921 return created && fromChildHandle(GetFocus()) is this; 1922 } 1923 1924 1925 /// 1926 @property void font(Font f) // setter 1927 { 1928 if(wfont is f) 1929 return; 1930 1931 wfont = f; 1932 if(isHandleCreated) 1933 SendMessageA(hwnd, WM_SETFONT, cast(WPARAM)wfont.handle, MAKELPARAM(true, 0)); 1934 onFontChanged(EventArgs.empty); 1935 1936 _propagateFontAmbience(); 1937 } 1938 1939 /// ditto 1940 @property Font font() // getter 1941 { 1942 if(!wfont) 1943 { 1944 if(parent) 1945 { 1946 return parent.font; 1947 } 1948 return defaultFont; 1949 } 1950 return wfont; 1951 } 1952 1953 1954 private void _propagateForeColorAmbience() 1955 { 1956 Color fc; 1957 fc = foreColor; 1958 1959 1960 void pa(Control pc) 1961 { 1962 foreach(Control ctrl; pc.ccollection) 1963 { 1964 if(Color.empty == ctrl.forec) // If default. 1965 { 1966 if(fc == ctrl.foreColor) // If same default. 1967 { 1968 ctrl.onForeColorChanged(EventArgs.empty); 1969 1970 pa(ctrl); // Recursive. 1971 } 1972 } 1973 } 1974 } 1975 1976 1977 pa(this); 1978 } 1979 1980 1981 /// 1982 protected void onForeColorChanged(EventArgs ea) 1983 { 1984 debug(EVENT_PRINT) 1985 { 1986 cprintf("{ Event: onForeColorChanged - Control %.*s }\n", name); 1987 } 1988 1989 foreColorChanged(this, ea); 1990 } 1991 1992 1993 /// 1994 @property void foreColor(Color c) // setter 1995 { 1996 if(c == forec) 1997 return; 1998 1999 forec = c; 2000 onForeColorChanged(EventArgs.empty); 2001 2002 _propagateForeColorAmbience(); 2003 if(isHandleCreated) 2004 invalidate(true); // Redraw! 2005 } 2006 2007 /// ditto 2008 @property Color foreColor() // getter 2009 { 2010 if(Color.empty == forec) 2011 { 2012 if(parent) 2013 { 2014 return parent.foreColor; 2015 } 2016 return defaultForeColor; 2017 } 2018 return forec; 2019 } 2020 2021 2022 /// 2023 // Doesn't cause a ControlCollection to be constructed so 2024 // it could improve performance when walking through children. 2025 final @property bool hasChildren() // getter 2026 { 2027 //return isHandleCreated && GetWindow(hwnd, GW_CHILD) != HWND.init; 2028 2029 if(isHandleCreated) 2030 { 2031 return GetWindow(hwnd, GW_CHILD) != HWND.init; 2032 } 2033 else 2034 { 2035 return ccollection.children.length != 0; 2036 } 2037 } 2038 2039 2040 /// 2041 final @property void height(int h) // setter 2042 { 2043 /* 2044 RECT rect; 2045 GetWindowRect(hwnd, &rect); 2046 SetWindowPos(hwnd, HWND.init, 0, 0, rect.right - rect.left, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); 2047 */ 2048 2049 setBoundsCore(0, 0, 0, h, BoundsSpecified.HEIGHT); 2050 } 2051 2052 /// ditto 2053 final @property int height() // getter 2054 { 2055 return wrect.height; 2056 } 2057 2058 2059 /// 2060 final @property bool isHandleCreated() // getter 2061 { 2062 return hwnd != HWND.init; 2063 } 2064 2065 2066 /// 2067 final @property void left(int l) // setter 2068 { 2069 /* 2070 RECT rect; 2071 GetWindowRect(hwnd, &rect); 2072 SetWindowPos(hwnd, HWND.init, l, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); 2073 */ 2074 2075 setBoundsCore(l, 0, 0, 0, BoundsSpecified.X); 2076 } 2077 2078 /// ditto 2079 final @property int left() // getter 2080 { 2081 return wrect.x; 2082 } 2083 2084 2085 /// Property: get or set the X and Y location of the control. 2086 final @property void location(Point pt) // setter 2087 { 2088 /* 2089 SetWindowPos(hwnd, HWND.init, pt.x, pt.y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); 2090 */ 2091 2092 setBoundsCore(pt.x, pt.y, 0, 0, BoundsSpecified.LOCATION); 2093 } 2094 2095 /// ditto 2096 final @property Point location() // getter 2097 { 2098 return wrect.location; 2099 } 2100 2101 2102 /// Currently depressed modifier keys. 2103 static @property Keys modifierKeys() // getter 2104 { 2105 // Is there a better way to do this? 2106 Keys ks = Keys.NONE; 2107 if(GetAsyncKeyState(VK_SHIFT) & 0x8000) 2108 ks |= Keys.SHIFT; 2109 if(GetAsyncKeyState(VK_MENU) & 0x8000) 2110 ks |= Keys.ALT; 2111 if(GetAsyncKeyState(VK_CONTROL) & 0x8000) 2112 ks|= Keys.CONTROL; 2113 return ks; 2114 } 2115 2116 2117 /// Currently depressed mouse buttons. 2118 static @property MouseButtons mouseButtons() // getter 2119 { 2120 MouseButtons result; 2121 2122 result = MouseButtons.NONE; 2123 if(GetSystemMetrics(SM_SWAPBUTTON)) 2124 { 2125 if(GetAsyncKeyState(VK_LBUTTON) & 0x8000) 2126 result |= MouseButtons.RIGHT; // Swapped. 2127 if(GetAsyncKeyState(VK_RBUTTON) & 0x8000) 2128 result |= MouseButtons.LEFT; // Swapped. 2129 } 2130 else 2131 { 2132 if(GetAsyncKeyState(VK_LBUTTON) & 0x8000) 2133 result |= MouseButtons.LEFT; 2134 if(GetAsyncKeyState(VK_RBUTTON) & 0x8000) 2135 result |= MouseButtons.RIGHT; 2136 } 2137 if(GetAsyncKeyState(VK_MBUTTON) & 0x8000) 2138 result |= MouseButtons.MIDDLE; 2139 2140 return result; 2141 } 2142 2143 2144 /// 2145 static @property Point mousePosition() // getter 2146 { 2147 Point pt; 2148 GetCursorPos(&pt.point); 2149 return pt; 2150 } 2151 2152 2153 /// Property: get or set the name of this control used in code. 2154 final @property void name(Dstring txt) // setter 2155 { 2156 _ctrlname = txt; 2157 } 2158 2159 /// ditto 2160 final @property Dstring name() // getter 2161 { 2162 return _ctrlname; 2163 } 2164 2165 2166 /// 2167 protected void onParentChanged(EventArgs ea) 2168 { 2169 debug(EVENT_PRINT) 2170 { 2171 cprintf("{ Event: onParentChanged - Control %.*s }\n", name); 2172 } 2173 2174 parentChanged(this, ea); 2175 } 2176 2177 2178 /+ 2179 /// 2180 // ea is the new parent. 2181 protected void onParentChanging(ControlEventArgs ea) 2182 { 2183 } 2184 +/ 2185 2186 2187 /// 2188 final Form findForm() 2189 { 2190 Form f; 2191 Control c; 2192 2193 c = this; 2194 for(;;) 2195 { 2196 f = cast(Form)c; 2197 if(f) 2198 break; 2199 c = c.parent; 2200 if(!c) 2201 return null; 2202 } 2203 return f; 2204 } 2205 2206 2207 /// 2208 final @property void parent(Control c) // setter 2209 { 2210 if(c is wparent) 2211 return; 2212 2213 if(!(_style() & WS_CHILD) || (_exStyle() & WS_EX_MDICHILD)) 2214 throw new DflException("Cannot add a top level control to a control"); 2215 2216 //scope ControlEventArgs pcea = new ControlEventArgs(c); 2217 //onParentChanging(pcea); 2218 2219 Control oldparent; 2220 _FixAmbientOld oldinfo; 2221 2222 oldparent = wparent; 2223 2224 if(oldparent) 2225 { 2226 oldinfo.set(oldparent); 2227 2228 if(!oldparent.isHandleCreated) 2229 { 2230 int oi = oldparent.controls.indexOf(this); 2231 //assert(-1 != oi); // Fails if the parent (and thus this) handles destroyed. 2232 if(-1 != oi) 2233 oldparent.controls._removeNotCreated(oi); 2234 } 2235 } 2236 else 2237 { 2238 oldinfo.set(this); 2239 } 2240 2241 scope ControlEventArgs cea = new ControlEventArgs(this); 2242 2243 if(c) 2244 { 2245 wparent = c; 2246 2247 // I want the destroy notification. Don't need it anymore. 2248 //c._exStyle(c._exStyle() & ~WS_EX_NOPARENTNOTIFY); 2249 2250 if(c.isHandleCreated) 2251 { 2252 cbits &= ~CBits.NEED_INIT_LAYOUT; 2253 2254 //if(created) 2255 if(isHandleCreated) 2256 { 2257 SetParent(hwnd, c.hwnd); 2258 } 2259 else 2260 { 2261 // If the parent is created, create me! 2262 createControl(); 2263 } 2264 2265 onParentChanged(EventArgs.empty); 2266 if(oldparent) 2267 oldparent._ctrlremoved(cea); 2268 c._ctrladded(cea); 2269 _fixAmbient(&oldinfo); 2270 2271 initLayout(); 2272 } 2273 else 2274 { 2275 // If the parent exists and isn't created, need to add 2276 // -this- to its children array. 2277 c.ccollection.children ~= this; 2278 2279 onParentChanged(EventArgs.empty); 2280 if(oldparent) 2281 oldparent._ctrlremoved(cea); 2282 c._ctrladded(cea); 2283 _fixAmbient(&oldinfo); 2284 2285 cbits |= CBits.NEED_INIT_LAYOUT; 2286 } 2287 } 2288 else 2289 { 2290 assert(c is null); 2291 //wparent = c; 2292 wparent = null; 2293 2294 if(isHandleCreated) 2295 SetParent(hwnd, HWND.init); 2296 2297 onParentChanged(EventArgs.empty); 2298 assert(oldparent !is null); 2299 oldparent._ctrlremoved(cea); 2300 _fixAmbient(&oldinfo); 2301 } 2302 } 2303 2304 /// ditto 2305 final @property Control parent() // getter 2306 { 2307 return wparent; 2308 } 2309 2310 2311 private final Control _fetchParent() 2312 { 2313 HWND hwParent = GetParent(hwnd); 2314 return fromHandle(hwParent); 2315 } 2316 2317 2318 // TODO: check implementation. 2319 private static HRGN dupHrgn(HRGN hrgn) 2320 { 2321 HRGN rdup = CreateRectRgn(0, 0, 1, 1); 2322 CombineRgn(rdup, hrgn, HRGN.init, RGN_COPY); 2323 return rdup; 2324 } 2325 2326 2327 /// 2328 final @property void region(Region rgn) // setter 2329 { 2330 if(isHandleCreated) 2331 { 2332 // Need to make a copy of the region. 2333 SetWindowRgn(hwnd, dupHrgn(rgn.handle), true); 2334 } 2335 2336 wregion = rgn; 2337 } 2338 2339 /// ditto 2340 final @property Region region() // getter 2341 { 2342 return wregion; 2343 } 2344 2345 2346 private final Region _fetchRegion() 2347 { 2348 HRGN hrgn = CreateRectRgn(0, 0, 1, 1); 2349 GetWindowRgn(hwnd, hrgn); 2350 return new Region(hrgn); // Owned because GetWindowRgn() gives a copy. 2351 } 2352 2353 2354 /// 2355 final @property int right() // getter 2356 { 2357 return wrect.right; 2358 } 2359 2360 2361 /+ 2362 @property void rightToLeft(bool byes) // setter 2363 { 2364 LONG wl = _exStyle(); 2365 if(byes) 2366 wl |= WS_EX_RTLREADING; 2367 else 2368 wl &= ~WS_EX_RTLREADING; 2369 _exStyle(wl); 2370 } 2371 2372 2373 @property bool rightToLeft() // getter 2374 { 2375 return (_exStyle() & WS_EX_RTLREADING) != 0; 2376 } 2377 +/ 2378 2379 2380 deprecated @property void rightToLeft(bool byes) // setter 2381 { 2382 rightToLeft = byes ? RightToLeft.YES : RightToLeft.NO; 2383 } 2384 2385 2386 package final void _fixRtol(RightToLeft val) 2387 { 2388 switch(val) 2389 { 2390 case RightToLeft.INHERIT: 2391 if(parent && parent.rightToLeft == RightToLeft.YES) 2392 { 2393 goto case RightToLeft.YES; 2394 } 2395 goto case RightToLeft.NO; 2396 2397 case RightToLeft.YES: 2398 _exStyle(_exStyle() | WS_EX_RTLREADING); 2399 break; 2400 2401 case RightToLeft.NO: 2402 _exStyle(_exStyle() & ~WS_EX_RTLREADING); 2403 break; 2404 2405 default: 2406 assert(0); 2407 } 2408 2409 //invalidate(true); // Children too in case they inherit. 2410 invalidate(false); // Since children are enumerated. 2411 } 2412 2413 2414 private void _propagateRtolAmbience() 2415 { 2416 RightToLeft rl; 2417 rl = rightToLeft; 2418 2419 2420 void pa(Control pc) 2421 { 2422 if(RightToLeft.INHERIT == pc.rtol) 2423 { 2424 //pc._fixRtol(rtol); 2425 pc._fixRtol(rl); // Set the specific parent value so it doesn't have to look up the chain. 2426 2427 foreach(Control ctrl; pc.ccollection) 2428 { 2429 ctrl.onRightToLeftChanged(EventArgs.empty); 2430 2431 pa(ctrl); 2432 } 2433 } 2434 } 2435 2436 2437 pa(this); 2438 } 2439 2440 2441 /// 2442 @property void rightToLeft(RightToLeft val) // setter 2443 { 2444 if(rtol != val) 2445 { 2446 rtol = val; 2447 onRightToLeftChanged(EventArgs.empty); 2448 _propagateRtolAmbience(); // Also sets the class style and invalidates. 2449 } 2450 } 2451 2452 /// ditto 2453 // Returns YES or NO; if inherited, returns parent's setting. 2454 @property RightToLeft rightToLeft() // getter 2455 { 2456 if(RightToLeft.INHERIT == rtol) 2457 { 2458 return parent ? parent.rightToLeft : RightToLeft.NO; 2459 } 2460 return rtol; 2461 } 2462 2463 2464 package struct _FixAmbientOld 2465 { 2466 Font font; 2467 Cursor cursor; 2468 Color backColor; 2469 Color foreColor; 2470 RightToLeft rightToLeft; 2471 //CBits cbits; 2472 bool enabled; 2473 2474 2475 void set(Control ctrl) 2476 { 2477 if(ctrl) 2478 { 2479 font = ctrl.font; 2480 cursor = ctrl.cursor; 2481 backColor = ctrl.backColor; 2482 foreColor = ctrl.foreColor; 2483 rightToLeft = ctrl.rightToLeft; 2484 //cbits = ctrl.cbits; 2485 enabled = ctrl.enabled; 2486 } 2487 /+else 2488 { 2489 font = null; 2490 cursor = null; 2491 backColor = Color.empty; 2492 foreColor = Color.empty; 2493 rightToLeft = RightToLeft.INHERIT; 2494 //cbits = CBits.init; 2495 enabled = true; 2496 }+/ 2497 } 2498 } 2499 2500 2501 // This is called when the inherited ambience changes. 2502 package final void _fixAmbient(_FixAmbientOld* oldinfo) 2503 { 2504 // Note: exception will screw things up. 2505 2506 _FixAmbientOld newinfo; 2507 if(parent) 2508 newinfo.set(parent); 2509 else 2510 newinfo.set(this); 2511 2512 if(RightToLeft.INHERIT == rtol) 2513 { 2514 if(newinfo.rightToLeft !is oldinfo.rightToLeft) 2515 { 2516 onRightToLeftChanged(EventArgs.empty); 2517 _propagateRtolAmbience(); 2518 } 2519 } 2520 2521 if(Color.empty == backc) 2522 { 2523 if(newinfo.backColor !is oldinfo.backColor) 2524 { 2525 onBackColorChanged(EventArgs.empty); 2526 _propagateBackColorAmbience(); 2527 } 2528 } 2529 2530 if(Color.empty == forec) 2531 { 2532 if(newinfo.foreColor !is oldinfo.foreColor) 2533 { 2534 onForeColorChanged(EventArgs.empty); 2535 _propagateForeColorAmbience(); 2536 } 2537 } 2538 2539 if(!wfont) 2540 { 2541 if(newinfo.font !is oldinfo.font) 2542 { 2543 onFontChanged(EventArgs.empty); 2544 _propagateFontAmbience(); 2545 } 2546 } 2547 2548 if(!wcurs) 2549 { 2550 if(newinfo.cursor !is oldinfo.cursor) 2551 { 2552 onCursorChanged(EventArgs.empty); 2553 _propagateCursorAmbience(); 2554 } 2555 } 2556 2557 /+ 2558 if(newinfo.enabled != oldinfo.enabled) 2559 { 2560 if(cbits & CBits.ENABLED) 2561 { 2562 _venabled(newinfo.enabled); 2563 _propagateEnabledAmbience(); 2564 } 2565 } 2566 +/ 2567 } 2568 2569 2570 /+ 2571 package final void _fixAmbientChildren() 2572 { 2573 foreach(Control ctrl; ccollection.children) 2574 { 2575 ctrl._fixAmbient(); 2576 } 2577 } 2578 +/ 2579 2580 2581 /// 2582 final @property void size(Size sz) // setter 2583 { 2584 /* 2585 SetWindowPos(hwnd, HWND.init, 0, 0, sz.width, sz.height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); 2586 */ 2587 2588 setBoundsCore(0, 0, sz.width, sz.height, BoundsSpecified.SIZE); 2589 } 2590 2591 /// ditto 2592 final @property Size size() // getter 2593 { 2594 return wrect.size; // struct Size, not sizeof. 2595 } 2596 2597 2598 /+ 2599 final @property void tabIndex(int i) // setter 2600 { 2601 // TODO: ? 2602 } 2603 2604 2605 final @property int tabIndex() // getter 2606 { 2607 return tabidx; 2608 } 2609 +/ 2610 2611 2612 // Use -zIndex- instead. 2613 // -tabIndex- may return different values in the future. 2614 deprecated int tabIndex() // getter 2615 { 2616 return zIndex; 2617 } 2618 2619 2620 /// 2621 final @property int zIndex() // getter 2622 out(result) 2623 { 2624 assert(result >= 0); 2625 } 2626 body 2627 { 2628 if(!parent) 2629 return 0; 2630 2631 if(isHandleCreated) 2632 { 2633 GetZIndex gzi; 2634 gzi.find = this; 2635 int index; 2636 int tmp; 2637 2638 BOOL getZIndexCallback(HWND hWnd) 2639 { 2640 if(hWnd is hwnd) 2641 { 2642 index = tmp; 2643 return FALSE; // Stop, found it. 2644 } 2645 2646 auto ctrl = Control.fromHandle(hWnd); 2647 if(ctrl && ctrl.parent is parent) 2648 { 2649 tmp++; 2650 } 2651 2652 return TRUE; // Keep looking. 2653 } 2654 2655 enumChildWindows(parent.hwnd, &getZIndexCallback); 2656 return index; 2657 } 2658 else 2659 { 2660 return parent.controls.indexOf(this); 2661 } 2662 } 2663 2664 2665 /// 2666 // True if control can be tabbed to. 2667 final @property void tabStop(bool byes) // setter 2668 { 2669 LONG wl = _style(); 2670 if(byes) 2671 wl |= WS_TABSTOP; 2672 else 2673 wl &= ~WS_TABSTOP; 2674 _style(wl); 2675 } 2676 2677 /// ditto 2678 final @property bool tabStop() // getter 2679 { 2680 return (_style() & WS_TABSTOP) != 0; 2681 } 2682 2683 2684 /// Property: get or set additional data tagged onto the control. 2685 final @property void tag(Object o) // setter 2686 { 2687 otag = o; 2688 } 2689 2690 /// ditto 2691 final @property Object tag() // getter 2692 { 2693 return otag; 2694 } 2695 2696 2697 private final Dstring _fetchText() 2698 { 2699 return dfl.internal.utf.getWindowText(hwnd); 2700 } 2701 2702 2703 /// 2704 @property void text(Dstring txt) // setter 2705 { 2706 if(isHandleCreated) 2707 { 2708 if(ctrlStyle & ControlStyles.CACHE_TEXT) 2709 { 2710 //if(wtext == txt) 2711 // return; 2712 wtext = txt; 2713 } 2714 2715 dfl.internal.utf.setWindowText(hwnd, txt); 2716 } 2717 else 2718 { 2719 wtext = txt; 2720 } 2721 } 2722 2723 /// ditto 2724 @property Dstring text() // getter 2725 { 2726 if(isHandleCreated) 2727 { 2728 if(ctrlStyle & ControlStyles.CACHE_TEXT) 2729 return wtext; 2730 2731 return _fetchText(); 2732 } 2733 else 2734 { 2735 return wtext; 2736 } 2737 } 2738 2739 2740 /// 2741 final @property void top(int t) // setter 2742 { 2743 setBoundsCore(0, t, 0, 0, BoundsSpecified.Y); 2744 } 2745 2746 /// ditto 2747 final @property int top() // getter 2748 { 2749 return wrect.y; 2750 } 2751 2752 2753 /// Returns the topmost Control related to this control. 2754 // Returns the owner control that has no parent. 2755 // Returns this Control if no owner ? 2756 final @property Control topLevelControl() // getter 2757 { 2758 if(isHandleCreated) 2759 { 2760 HWND hwCurrent = hwnd; 2761 HWND hwParent; 2762 2763 for(;;) 2764 { 2765 hwParent = GetParent(hwCurrent); // This gets the top-level one, whereas the previous code jumped owners. 2766 if(!hwParent) 2767 break; 2768 2769 hwCurrent = hwParent; 2770 } 2771 2772 return fromHandle(hwCurrent); 2773 } 2774 else 2775 { 2776 Control ctrl; 2777 ctrl = this; 2778 while(ctrl.parent) 2779 { 2780 ctrl = ctrl.parent; // This shouldn't jump owners.. 2781 } 2782 return ctrl; 2783 } 2784 } 2785 2786 2787 /+ 2788 private DWORD _fetchVisible() 2789 { 2790 //return IsWindowVisible(hwnd) != FALSE; 2791 wstyle = GetWindowLongA(hwnd, GWL_STYLE); 2792 return wstyle & WS_VISIBLE; 2793 } 2794 +/ 2795 2796 2797 /// 2798 final @property void visible(bool byes) // setter 2799 { 2800 setVisibleCore(byes); 2801 } 2802 2803 /// ditto 2804 final @property bool visible() // getter 2805 { 2806 //if(isHandleCreated) 2807 // wstyle = GetWindowLongA(hwnd, GWL_STYLE); // ... 2808 //return (wstyle & WS_VISIBLE) != 0; 2809 return (cbits & CBits.VISIBLE) != 0; 2810 } 2811 2812 2813 /// 2814 final @property void width(int w) // setter 2815 { 2816 setBoundsCore(0, 0, w, 0, BoundsSpecified.WIDTH); 2817 } 2818 2819 /// ditto 2820 final @property int width() // getter 2821 { 2822 return wrect.width; 2823 } 2824 2825 2826 /// 2827 final void sendToBack() 2828 { 2829 if(!isHandleCreated) 2830 { 2831 if(parent) 2832 parent.ccollection._simple_front(this); 2833 return; 2834 } 2835 2836 SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 2837 } 2838 2839 2840 /// 2841 final void bringToFront() 2842 { 2843 if(!isHandleCreated) 2844 { 2845 if(parent) 2846 parent.ccollection._simple_back(this); 2847 return; 2848 } 2849 2850 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 2851 //BringWindowToTop(hwnd); 2852 } 2853 2854 2855 deprecated alias bringUpOne zIndexUp; 2856 2857 /// 2858 // Move up one. 2859 final void bringUpOne() 2860 { 2861 if(!isHandleCreated) 2862 { 2863 if(parent) 2864 parent.ccollection._simple_front_one(this); 2865 return; 2866 } 2867 2868 HWND hw; 2869 2870 // Need to move back twice because the previous one already precedes this one. 2871 hw = GetWindow(hwnd, GW_HWNDPREV); 2872 if(!hw) 2873 { 2874 hw = HWND_TOP; 2875 } 2876 else 2877 { 2878 hw = GetWindow(hw, GW_HWNDPREV); 2879 if(!hw) 2880 hw = HWND_TOP; 2881 } 2882 2883 SetWindowPos(hwnd, hw, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 2884 } 2885 2886 2887 deprecated alias sendBackOne zIndexDown; 2888 2889 /// 2890 // Move back one. 2891 final void sendBackOne() 2892 { 2893 if(!isHandleCreated) 2894 { 2895 if(parent) 2896 parent.ccollection._simple_back_one(this); 2897 return; 2898 } 2899 2900 HWND hw; 2901 2902 hw = GetWindow(hwnd, GW_HWNDNEXT); 2903 if(!hw) 2904 hw = HWND_BOTTOM; 2905 2906 SetWindowPos(hwnd, hw, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 2907 } 2908 2909 2910 // Note: true if no children, even if this not created. 2911 package final @property bool areChildrenCreated() // getter 2912 { 2913 return !ccollection.children.length; 2914 } 2915 2916 2917 package final void createChildren() 2918 { 2919 assert(isHandleCreated); 2920 2921 Control[] ctrls; 2922 ctrls = ccollection.children; 2923 ccollection.children = null; 2924 2925 foreach(Control ctrl; ctrls) 2926 { 2927 assert(ctrl.parent is this); 2928 assert(!(ctrl is null)); 2929 assert(ctrl); 2930 ctrl.createControl(); 2931 } 2932 } 2933 2934 2935 /// 2936 // Force creation of the window and its child controls. 2937 final void createControl() 2938 { 2939 createHandle(); 2940 2941 // Called in WM_CREATE also. 2942 createChildren(); 2943 } 2944 2945 2946 /// Returns a new Graphics object for this control, creating the control handle if necessary. 2947 final Graphics createGraphics() 2948 { 2949 HDC hdc = GetDC(handle); // Create handle as necessary. 2950 SetTextColor(hdc, foreColor.toRgb()); 2951 return new CommonGraphics(hwnd, hdc); 2952 } 2953 2954 2955 version(DFL_NO_DRAG_DROP) {} else 2956 { 2957 private static class DropTarget: DflComObject, IDropTarget 2958 { 2959 this(Control ctrl) 2960 { 2961 this.ctrl = ctrl; 2962 } 2963 ~this() 2964 { 2965 if (dataObj) 2966 { 2967 GC.removeRoot(cast(void*)dataObj); 2968 destroy(dataObj); 2969 } 2970 } 2971 2972 2973 extern(Windows): 2974 override HRESULT QueryInterface(IID* riid, void** ppv) 2975 { 2976 if(*riid == _IID_IDropTarget) 2977 { 2978 *ppv = cast(void*)cast(IDropTarget)this; 2979 AddRef(); 2980 return S_OK; 2981 } 2982 else if(*riid == _IID_IUnknown) 2983 { 2984 *ppv = cast(void*)cast(IUnknown)this; 2985 AddRef(); 2986 return S_OK; 2987 } 2988 else 2989 { 2990 *ppv = null; 2991 return E_NOINTERFACE; 2992 } 2993 } 2994 2995 2996 HRESULT DragEnter(dfl.internal.wincom.IDataObject pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 2997 { 2998 HRESULT result; 2999 3000 try 3001 { 3002 //dataObj = new ComToDdataObject(pDataObject); 3003 ensureDataObj(pDataObject); 3004 3005 scope DragEventArgs ea = new DragEventArgs(dataObj, cast(int)grfKeyState, pt.x, pt.y, 3006 cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ? 3007 ctrl.onDragEnter(ea); 3008 *pdwEffect = ea.effect; 3009 3010 result = S_OK; 3011 } 3012 catch(DThrowable e) 3013 { 3014 Application.onThreadException(e); 3015 3016 result = E_UNEXPECTED; 3017 } 3018 3019 return result; 3020 } 3021 3022 3023 HRESULT DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 3024 { 3025 HRESULT result; 3026 3027 try 3028 { 3029 assert(dataObj !is null); 3030 3031 scope DragEventArgs ea = new DragEventArgs(dataObj, cast(int)grfKeyState, pt.x, pt.y, 3032 cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ? 3033 ctrl.onDragOver(ea); 3034 *pdwEffect = ea.effect; 3035 3036 result = S_OK; 3037 } 3038 catch(DThrowable e) 3039 { 3040 Application.onThreadException(e); 3041 3042 result = E_UNEXPECTED; 3043 } 3044 3045 return result; 3046 } 3047 3048 3049 HRESULT DragLeave() 3050 { 3051 HRESULT result; 3052 3053 try 3054 { 3055 ctrl.onDragLeave(EventArgs.empty); 3056 3057 killDataObj(); 3058 3059 result = S_OK; 3060 } 3061 catch(DThrowable e) 3062 { 3063 Application.onThreadException(e); 3064 3065 result = E_UNEXPECTED; 3066 } 3067 3068 return result; 3069 } 3070 3071 3072 HRESULT Drop(dfl.internal.wincom.IDataObject pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 3073 { 3074 HRESULT result; 3075 3076 try 3077 { 3078 //assert(dataObj !is null); 3079 ensureDataObj(pDataObject); 3080 3081 scope DragEventArgs ea = new DragEventArgs(dataObj, cast(int)grfKeyState, pt.x, pt.y, 3082 cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ? 3083 ctrl.onDragDrop(ea); 3084 *pdwEffect = ea.effect; 3085 3086 result = S_OK; 3087 } 3088 catch(DThrowable e) 3089 { 3090 Application.onThreadException(e); 3091 3092 result = E_UNEXPECTED; 3093 } 3094 3095 return result; 3096 } 3097 3098 3099 private: 3100 3101 Control ctrl; 3102 //dfl.data.IDataObject dataObj; 3103 ComToDdataObject dataObj; 3104 3105 3106 void ensureDataObj(dfl.internal.wincom.IDataObject pDataObject) 3107 { 3108 if(!dataObj) 3109 { 3110 dataObj = new ComToDdataObject(pDataObject); 3111 GC.addRoot(cast(void*)dataObj); 3112 } 3113 else if (!dataObj.isSameDataObject(pDataObject)) 3114 { 3115 GC.removeRoot(cast(void*)dataObj); 3116 dataObj = new ComToDdataObject(pDataObject); 3117 GC.addRoot(cast(void*)dataObj); 3118 } 3119 } 3120 3121 3122 void killDataObj() 3123 { 3124 // Can't do this because the COM object might still need to be released elsewhere. 3125 //delete dataObj; 3126 //dataObj = null; 3127 } 3128 } 3129 3130 3131 /// 3132 protected void onDragLeave(EventArgs ea) 3133 { 3134 dragLeave(this, ea); 3135 } 3136 3137 3138 /// 3139 protected void onDragEnter(DragEventArgs ea) 3140 { 3141 dragEnter(this, ea); 3142 } 3143 3144 3145 /// 3146 protected void onDragOver(DragEventArgs ea) 3147 { 3148 dragOver(this, ea); 3149 } 3150 3151 3152 /// 3153 protected void onDragDrop(DragEventArgs ea) 3154 { 3155 dragDrop(this, ea); 3156 } 3157 3158 3159 private static class DropSource: DflComObject, IDropSource 3160 { 3161 this(Control ctrl) 3162 { 3163 this.ctrl = ctrl; 3164 mbtns = Control.mouseButtons; 3165 } 3166 3167 3168 extern(Windows): 3169 override HRESULT QueryInterface(IID* riid, void** ppv) 3170 { 3171 if(*riid == _IID_IDropSource) 3172 { 3173 *ppv = cast(void*)cast(IDropSource)this; 3174 AddRef(); 3175 return S_OK; 3176 } 3177 else if(*riid == _IID_IUnknown) 3178 { 3179 *ppv = cast(void*)cast(IUnknown)this; 3180 AddRef(); 3181 return S_OK; 3182 } 3183 else 3184 { 3185 *ppv = null; 3186 return E_NOINTERFACE; 3187 } 3188 } 3189 3190 3191 HRESULT QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) 3192 { 3193 HRESULT result; 3194 3195 try 3196 { 3197 DragAction act; 3198 3199 if(fEscapePressed) 3200 { 3201 act = cast(DragAction)DragAction.CANCEL; 3202 } 3203 else 3204 { 3205 if(mbtns & MouseButtons.LEFT) 3206 { 3207 if(!(grfKeyState & MK_LBUTTON)) 3208 { 3209 act = cast(DragAction)DragAction.DROP; 3210 goto qdoit; 3211 } 3212 } 3213 else 3214 { 3215 if(grfKeyState & MK_LBUTTON) 3216 { 3217 act = cast(DragAction)DragAction.CANCEL; 3218 goto qdoit; 3219 } 3220 } 3221 if(mbtns & MouseButtons.RIGHT) 3222 { 3223 if(!(grfKeyState & MK_RBUTTON)) 3224 { 3225 act = cast(DragAction)DragAction.DROP; 3226 goto qdoit; 3227 } 3228 } 3229 else 3230 { 3231 if(grfKeyState & MK_RBUTTON) 3232 { 3233 act = cast(DragAction)DragAction.CANCEL; 3234 goto qdoit; 3235 } 3236 } 3237 if(mbtns & MouseButtons.MIDDLE) 3238 { 3239 if(!(grfKeyState & MK_MBUTTON)) 3240 { 3241 act = cast(DragAction)DragAction.DROP; 3242 goto qdoit; 3243 } 3244 } 3245 else 3246 { 3247 if(grfKeyState & MK_MBUTTON) 3248 { 3249 act = cast(DragAction)DragAction.CANCEL; 3250 goto qdoit; 3251 } 3252 } 3253 3254 act = cast(DragAction)DragAction.CONTINUE; 3255 } 3256 3257 qdoit: 3258 scope QueryContinueDragEventArgs ea = new QueryContinueDragEventArgs(cast(int)grfKeyState, 3259 fEscapePressed != FALSE, act); // ? 3260 ctrl.onQueryContinueDrag(ea); 3261 3262 result = cast(HRESULT)ea.action; 3263 } 3264 catch(DThrowable e) 3265 { 3266 Application.onThreadException(e); 3267 3268 result = E_UNEXPECTED; 3269 } 3270 3271 return result; 3272 } 3273 3274 3275 HRESULT GiveFeedback(DWORD dwEffect) 3276 { 3277 HRESULT result; 3278 3279 try 3280 { 3281 scope GiveFeedbackEventArgs ea = new GiveFeedbackEventArgs(cast(DragDropEffects)dwEffect, true); 3282 ctrl.onGiveFeedback(ea); 3283 3284 result = ea.useDefaultCursors ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK; 3285 } 3286 catch(DThrowable e) 3287 { 3288 Application.onThreadException(e); 3289 3290 result = E_UNEXPECTED; 3291 } 3292 3293 return result; 3294 } 3295 3296 3297 private: 3298 Control ctrl; 3299 MouseButtons mbtns; 3300 } 3301 3302 3303 /// 3304 protected void onQueryContinueDrag(QueryContinueDragEventArgs ea) 3305 { 3306 queryContinueDrag(this, ea); 3307 } 3308 3309 3310 /// 3311 protected void onGiveFeedback(GiveFeedbackEventArgs ea) 3312 { 3313 giveFeedback(this, ea); 3314 } 3315 3316 3317 /// Perform a drag/drop operation. 3318 final DragDropEffects doDragDrop(dfl.data.IDataObject dataObj, DragDropEffects allowedEffects) 3319 { 3320 Object foo = cast(Object)dataObj; // Hold a reference to the Object... 3321 3322 DWORD effect; 3323 DropSource dropsrc; 3324 dfl.internal.wincom.IDataObject dropdata; 3325 3326 dropsrc = new DropSource(this); 3327 dropdata = new DtoComDataObject(dataObj); 3328 3329 // dataObj seems to be killed too early. 3330 switch(DoDragDrop(dropdata, dropsrc, cast(DWORD)allowedEffects, &effect)) 3331 { 3332 case DRAGDROP_S_DROP: // All good. 3333 break; 3334 3335 case DRAGDROP_S_CANCEL: 3336 return DragDropEffects.NONE; // ? 3337 3338 default: 3339 throw new DflException("Unable to complete drag-drop operation"); 3340 } 3341 3342 return cast(DragDropEffects)effect; 3343 } 3344 3345 /// ditto 3346 final DragDropEffects doDragDrop(Data obj, DragDropEffects allowedEffects) 3347 { 3348 dfl.data.IDataObject dd; 3349 dd = new DataObject; 3350 dd.setData(obj); 3351 return doDragDrop(dd, allowedEffects); 3352 } 3353 } 3354 3355 3356 override Dequ opEquals(Object o) 3357 { 3358 Control ctrl = cast(Control)o; 3359 if(!ctrl) 3360 return 0; // Not equal. 3361 return opEquals(ctrl); 3362 } 3363 3364 3365 Dequ opEquals(Control ctrl) 3366 { 3367 if(!isHandleCreated) 3368 return super.opEquals(ctrl); 3369 return hwnd == ctrl.hwnd; 3370 } 3371 3372 3373 override int opCmp(Object o) 3374 { 3375 Control ctrl = cast(Control)o; 3376 if(!ctrl) 3377 return -1; 3378 return opCmp(ctrl); 3379 } 3380 3381 3382 int opCmp(Control ctrl) 3383 { 3384 if(!isHandleCreated || hwnd != ctrl.hwnd) 3385 return super.opCmp(ctrl); 3386 return 0; 3387 } 3388 3389 3390 /// 3391 final bool focus() 3392 { 3393 return SetFocus(hwnd) != HWND.init; 3394 } 3395 3396 3397 /// Returns the Control instance from one of its window handles, or null if none. 3398 // Finds controls that own more than one handle. 3399 // A combo box has several HWNDs, this would return the 3400 // correct combo box control if any of those handles are 3401 // provided. 3402 static Control fromChildHandle(HWND hwChild) 3403 { 3404 Control result; 3405 for(;;) 3406 { 3407 if(!hwChild) 3408 return null; 3409 3410 result = fromHandle(hwChild); 3411 if(result) 3412 return result; 3413 3414 hwChild = GetParent(hwChild); 3415 } 3416 } 3417 3418 3419 /// Returns the Control instance from its window handle, or null if none. 3420 static Control fromHandle(HWND hw) 3421 { 3422 return Application.lookupHwnd(hw); 3423 } 3424 3425 3426 /// 3427 final Control getChildAtPoint(Point pt) 3428 { 3429 HWND hwChild; 3430 hwChild = ChildWindowFromPoint(hwnd, pt.point); 3431 if(!hwChild) 3432 return null; 3433 return fromChildHandle(hwChild); 3434 } 3435 3436 3437 /// 3438 final void hide() 3439 { 3440 setVisibleCore(false); 3441 } 3442 3443 /// ditto 3444 final void show() 3445 { 3446 /* 3447 ShowWindow(hwnd, SW_SHOW); 3448 doShow(); 3449 */ 3450 3451 setVisibleCore(true); 3452 } 3453 3454 3455 package final void redrawEntire() 3456 { 3457 if(hwnd) 3458 { 3459 SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_DRAWFRAME | SWP_NOMOVE 3460 | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 3461 } 3462 } 3463 3464 3465 package final void recalcEntire() 3466 { 3467 if(hwnd) 3468 { 3469 SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE 3470 | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 3471 } 3472 } 3473 3474 3475 /// 3476 final void invalidate() 3477 { 3478 if(!hwnd) 3479 return; 3480 3481 RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN); 3482 } 3483 3484 /// ditto 3485 final void invalidate(bool andChildren) 3486 { 3487 if(!hwnd) 3488 return; 3489 3490 RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN)); 3491 } 3492 3493 /// ditto 3494 final void invalidate(Rect r) 3495 { 3496 if(!hwnd) 3497 return; 3498 3499 RECT rect; 3500 r.getRect(&rect); 3501 3502 RedrawWindow(hwnd, &rect, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN); 3503 } 3504 3505 /// ditto 3506 final void invalidate(Rect r, bool andChildren) 3507 { 3508 if(!hwnd) 3509 return; 3510 3511 RECT rect; 3512 r.getRect(&rect); 3513 3514 RedrawWindow(hwnd, &rect, HRGN.init, RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN)); 3515 } 3516 3517 /// ditto 3518 final void invalidate(Region rgn) 3519 { 3520 if(!hwnd) 3521 return; 3522 3523 RedrawWindow(hwnd, null, rgn.handle, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN); 3524 } 3525 3526 /// ditto 3527 final void invalidate(Region rgn, bool andChildren) 3528 { 3529 if(!hwnd) 3530 return; 3531 3532 RedrawWindow(hwnd, null, rgn.handle, RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN)); 3533 } 3534 3535 3536 /// 3537 // Redraws the entire control, including nonclient area. 3538 final void redraw() 3539 { 3540 if(!hwnd) 3541 return; 3542 3543 RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); 3544 } 3545 3546 3547 /// Returns true if the window does not belong to the current thread. 3548 @property bool invokeRequired() // getter 3549 { 3550 DWORD tid = GetWindowThreadProcessId(hwnd, null); 3551 return tid != GetCurrentThreadId(); 3552 } 3553 3554 3555 private static void badInvokeHandle() 3556 { 3557 //throw new DflException("Must invoke after creating handle"); 3558 throw new DflException("Must invoke with created handle"); 3559 } 3560 3561 3562 /// Synchronously calls a delegate in this Control's thread. This function is thread safe and exceptions are propagated to the caller. 3563 // Exceptions are propagated back to the caller of invoke(). 3564 final Object invoke(Object delegate(Object[]) dg, Object[] args ...) 3565 { 3566 if(!hwnd) 3567 badInvokeHandle(); 3568 3569 InvokeData inv; 3570 inv.dg = dg; 3571 inv.args = args; 3572 3573 if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE, cast(LRESULT)&inv)) 3574 throw new DflException("Invoke failure"); 3575 if(inv.exception) 3576 throw inv.exception; 3577 3578 return inv.result; 3579 } 3580 3581 /// ditto 3582 final void invoke(void delegate() dg) 3583 { 3584 if(!hwnd) 3585 badInvokeHandle(); 3586 3587 InvokeSimpleData inv; 3588 inv.dg = dg; 3589 3590 if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE_SIMPLE, cast(LRESULT)&inv)) 3591 throw new DflException("Invoke failure"); 3592 if(inv.exception) 3593 throw inv.exception; 3594 } 3595 3596 3597 /** Asynchronously calls a function after the window message queue processes its current messages. 3598 It is generally not safe to pass references to the delayed function. 3599 Exceptions are not propagated to the caller. 3600 **/ 3601 // Extra. 3602 // Exceptions will be passed to Application.onThreadException() and 3603 // trigger the threadException event or the default exception dialog. 3604 final void delayInvoke(void function() fn) 3605 { 3606 if(!hwnd) 3607 badInvokeHandle(); 3608 3609 assert(!invokeRequired); 3610 3611 static assert(fn.sizeof <= LPARAM.sizeof); 3612 PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE, cast(LPARAM)fn); 3613 } 3614 3615 /// ditto 3616 // Extra. 3617 // Exceptions will be passed to Application.onThreadException() and 3618 // trigger the threadException event or the default exception dialog. 3619 // Copy of params are passed to fn, they do not exist after it returns. 3620 // It is unsafe to pass references to a delayed function. 3621 final void delayInvoke(void function(Control, size_t[]) fn, size_t[] params ...) 3622 { 3623 if(!hwnd) 3624 badInvokeHandle(); 3625 3626 assert(!invokeRequired); 3627 3628 static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof); 3629 3630 DflInvokeParam* p; 3631 p = cast(DflInvokeParam*)dfl.internal.clib.malloc( 3632 (DflInvokeParam.sizeof - size_t.sizeof) 3633 + params.length * size_t.sizeof); 3634 if(!p) 3635 throw new OomException(); 3636 3637 p.fp = fn; 3638 p.nparams = params.length; 3639 p.params.ptr[0 .. params.length] = params[]; 3640 3641 PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, cast(LPARAM)p); 3642 } 3643 3644 deprecated alias delayInvoke beginInvoke; 3645 3646 3647 /// 3648 static bool isMnemonic(dchar charCode, Dstring text) 3649 { 3650 uint ui; 3651 for(ui = 0; ui != text.length; ui++) 3652 { 3653 if('&' == text[ui]) 3654 { 3655 if(++ui == text.length) 3656 break; 3657 if('&' == text[ui]) // && means literal & so skip it. 3658 continue; 3659 dchar dch; 3660 dch = utf8stringGetUtf32char(text, ui); 3661 return utf32charToLower(charCode) == utf32charToLower(dch); 3662 } 3663 } 3664 return false; 3665 } 3666 3667 3668 /// Converts a screen Point to a client Point. 3669 final Point pointToClient(Point pt) 3670 { 3671 ScreenToClient(hwnd, &pt.point); 3672 return pt; 3673 } 3674 3675 3676 /// Converts a client Point to a screen Point. 3677 final Point pointToScreen(Point pt) 3678 { 3679 ClientToScreen(hwnd, &pt.point); 3680 return pt; 3681 } 3682 3683 3684 /// Converts a screen Rectangle to a client Rectangle. 3685 final Rect rectangleToClient(Rect r) 3686 { 3687 RECT rect; 3688 r.getRect(&rect); 3689 3690 MapWindowPoints(HWND.init, hwnd, cast(POINT*)&rect, 2); 3691 return Rect(&rect); 3692 } 3693 3694 3695 /// Converts a client Rectangle to a screen Rectangle. 3696 final Rect rectangleToScreen(Rect r) 3697 { 3698 RECT rect; 3699 r.getRect(&rect); 3700 3701 MapWindowPoints(hwnd, HWND.init, cast(POINT*)&rect, 2); 3702 return Rect(&rect); 3703 } 3704 3705 3706 /// 3707 // Return true if processed. 3708 bool preProcessMessage(ref Message msg) 3709 { 3710 return false; 3711 } 3712 3713 3714 /// 3715 final Size getAutoScaleSize(Font f) 3716 { 3717 Size result; 3718 Graphics g; 3719 g = createGraphics(); 3720 result = g.getScaleSize(f); 3721 g.dispose(); 3722 return result; 3723 } 3724 3725 /// ditto 3726 final Size getAutoScaleSize() 3727 { 3728 return getAutoScaleSize(font); 3729 } 3730 3731 3732 /// 3733 void refresh() 3734 { 3735 invalidate(true); 3736 } 3737 3738 3739 /// 3740 void resetBackColor() 3741 { 3742 //backColor = defaultBackColor; 3743 backColor = Color.empty; 3744 } 3745 3746 3747 /// 3748 void resetCursor() 3749 { 3750 //cursor = new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false); 3751 cursor = null; 3752 } 3753 3754 3755 /// 3756 void resetFont() 3757 { 3758 //font = defaultFont; 3759 font = null; 3760 } 3761 3762 3763 /// 3764 void resetForeColor() 3765 { 3766 //foreColor = defaultForeColor; 3767 foreColor = Color.empty; 3768 } 3769 3770 3771 /// 3772 void resetRightToLeft() 3773 { 3774 //rightToLeft = false; 3775 rightToLeft = RightToLeft.INHERIT; 3776 } 3777 3778 3779 /// 3780 void resetText() 3781 { 3782 //text = ""; 3783 text = null; 3784 } 3785 3786 3787 /// 3788 // Just allow layout recalc, but don't do it right now. 3789 final void resumeLayout() 3790 { 3791 //_allowLayout = true; 3792 if(_disallowLayout) 3793 _disallowLayout--; 3794 } 3795 3796 /// ditto 3797 // Allow layout recalc, only do it now if -byes- is true. 3798 final void resumeLayout(bool byes) 3799 { 3800 if(_disallowLayout) 3801 _disallowLayout--; 3802 3803 // This is correct. 3804 if(byes) 3805 { 3806 if(!_disallowLayout) 3807 alayout(null); 3808 } 3809 } 3810 3811 3812 /// 3813 final void suspendLayout() 3814 { 3815 //_allowLayout = false; 3816 _disallowLayout++; 3817 } 3818 3819 3820 final void performLayout(Control affectedControl) 3821 { 3822 alayout(affectedControl, false); 3823 } 3824 3825 3826 final void performLayout() 3827 { 3828 return performLayout(this); 3829 } 3830 3831 3832 /+ 3833 // TODO: implement. 3834 3835 // Scale both height and width to -ratio-. 3836 final void scale(float ratio) 3837 { 3838 scaleCore(ratio, ratio); 3839 } 3840 3841 3842 // Scale -width- and -height- ratios. 3843 final void scale(float width, float height) 3844 { 3845 scaleCore(width, height); 3846 } 3847 3848 3849 // Also scales child controls recursively. 3850 protected void scaleCore(float width, float height) 3851 { 3852 suspendLayout(); 3853 3854 // ... 3855 3856 resumeLayout(); 3857 } 3858 +/ 3859 3860 3861 private static bool _eachild(HWND hw, bool delegate(HWND hw) callback, ref size_t xiter, bool nested) 3862 { 3863 for(; hw; hw = GetWindow(hw, GW_HWNDNEXT)) 3864 { 3865 if(!xiter) 3866 return false; 3867 xiter--; 3868 3869 LONG st = GetWindowLongA(hw, GWL_STYLE); 3870 if(!(st & WS_VISIBLE)) 3871 continue; 3872 if(st & WS_DISABLED) 3873 continue; 3874 3875 if(!callback(hw)) 3876 return false; 3877 3878 if(nested) 3879 { 3880 //LONG exst = GetWindowLongA(hw, GWL_EXSTYLE); 3881 //if(exst & WS_EX_CONTROLPARENT) // It's no longer added. 3882 { 3883 HWND hwc = GetWindow(hw, GW_CHILD); 3884 if(hwc) 3885 { 3886 //if(!_eachild(hwc, callback, xiter, nested)) 3887 if(!_eachild(hwc, callback, xiter, true)) 3888 return false; 3889 } 3890 } 3891 } 3892 } 3893 return true; 3894 } 3895 3896 package static void eachGoodChildHandle(HWND hwparent, bool delegate(HWND hw) callback, bool nested = true) 3897 { 3898 HWND hw = GetWindow(hwparent, GW_CHILD); 3899 size_t xiter = 2000; 3900 _eachild(hw, callback, xiter, nested); 3901 } 3902 3903 3904 private static bool _isHwndControlSel(HWND hw) 3905 { 3906 Control c = Control.fromHandle(hw); 3907 return c && c.getStyle(ControlStyles.SELECTABLE); 3908 } 3909 3910 3911 package static void _dlgselnext(Form dlg, HWND hwcursel, bool forward, 3912 bool tabStopOnly = true, bool selectableOnly = false, 3913 bool nested = true, bool wrap = true, 3914 HWND hwchildrenof = null) 3915 { 3916 //assert(cast(Form)Control.fromHandle(hwdlg) !is null); 3917 3918 if(!hwchildrenof) 3919 hwchildrenof = dlg.handle; 3920 if(forward) 3921 { 3922 bool foundthis = false, tdone = false; 3923 HWND hwfirst; 3924 eachGoodChildHandle(hwchildrenof, 3925 (HWND hw) 3926 { 3927 assert(!tdone); 3928 if(hw == hwcursel) 3929 { 3930 foundthis = true; 3931 } 3932 else 3933 { 3934 if(!tabStopOnly || (GetWindowLongA(hw, GWL_STYLE) & WS_TABSTOP)) 3935 { 3936 if(!selectableOnly || _isHwndControlSel(hw)) 3937 { 3938 if(foundthis) 3939 { 3940 //DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hw, MAKELPARAM(true, 0)); 3941 dlg._selectChild(hw); 3942 tdone = true; 3943 return false; // Break. 3944 } 3945 else 3946 { 3947 if(HWND.init == hwfirst) 3948 hwfirst = hw; 3949 } 3950 } 3951 } 3952 } 3953 return true; // Continue. 3954 }, nested); 3955 if(!tdone && HWND.init != hwfirst) 3956 { 3957 // If it falls through without finding hwcursel, let it select the first one, even if not wrapping. 3958 if(wrap || !foundthis) 3959 { 3960 //DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hwfirst, MAKELPARAM(true, 0)); 3961 dlg._selectChild(hwfirst); 3962 } 3963 } 3964 } 3965 else 3966 { 3967 HWND hwprev; 3968 eachGoodChildHandle(hwchildrenof, 3969 (HWND hw) 3970 { 3971 if(hw == hwcursel) 3972 { 3973 if(HWND.init != hwprev) // Otherwise, keep looping and get last one. 3974 return false; // Break. 3975 if(!wrap) // No wrapping, so don't get last one. 3976 { 3977 assert(HWND.init == hwprev); 3978 return false; // Break. 3979 } 3980 } 3981 if(!tabStopOnly || (GetWindowLongA(hw, GWL_STYLE) & WS_TABSTOP)) 3982 { 3983 if(!selectableOnly || _isHwndControlSel(hw)) 3984 { 3985 hwprev = hw; 3986 } 3987 } 3988 return true; // Continue. 3989 }, nested); 3990 // If it falls through without finding hwcursel, let it select the last one, even if not wrapping. 3991 if(HWND.init != hwprev) 3992 //DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hwprev, MAKELPARAM(true, 0)); 3993 dlg._selectChild(hwprev); 3994 } 3995 } 3996 3997 3998 package final void _selectNextControl(Form ctrltoplevel, 3999 Control ctrl, bool forward, bool tabStopOnly, bool nested, bool wrap) 4000 { 4001 if(!created) 4002 return; 4003 4004 assert(ctrltoplevel !is null); 4005 assert(ctrltoplevel.isHandleCreated); 4006 4007 _dlgselnext(ctrltoplevel, 4008 (ctrl && ctrl.isHandleCreated) ? ctrl.handle : null, 4009 forward, tabStopOnly, !tabStopOnly, nested, wrap, 4010 this.handle); 4011 } 4012 4013 4014 package final void _selectThisControl() 4015 { 4016 4017 } 4018 4019 4020 // Only considers child controls of this control. 4021 final void selectNextControl(Control ctrl, bool forward, bool tabStopOnly, bool nested, bool wrap) 4022 { 4023 if(!created) 4024 return; 4025 4026 auto ctrltoplevel = findForm(); 4027 if(ctrltoplevel) 4028 return _selectNextControl(ctrltoplevel, ctrl, forward, tabStopOnly, nested, wrap); 4029 } 4030 4031 4032 /// 4033 final void select() 4034 { 4035 select(false, false); 4036 } 4037 4038 /// ditto 4039 // If -directed- is true, -forward- is used; otherwise, selects this control. 4040 // If -forward- is true, the next control in the tab order is selected, 4041 // otherwise the previous control in the tab order is selected. 4042 // Controls without style ControlStyles.SELECTABLE are skipped. 4043 void select(bool directed, bool forward) 4044 { 4045 if(!created) 4046 return; 4047 4048 auto ctrltoplevel = findForm(); 4049 if(ctrltoplevel && ctrltoplevel !is this) 4050 { 4051 /+ // Old... 4052 // Even if directed, ensure THIS one is selected first. 4053 if(!directed || hwnd != GetFocus()) 4054 { 4055 DefDlgProcA(ctrltoplevel.handle, WM_NEXTDLGCTL, cast(WPARAM)hwnd, MAKELPARAM(true, 0)); 4056 } 4057 4058 if(directed) 4059 { 4060 DefDlgProcA(ctrltoplevel.handle, WM_NEXTDLGCTL, !forward, MAKELPARAM(false, 0)); 4061 } 4062 +/ 4063 4064 if(directed) 4065 { 4066 _dlgselnext(ctrltoplevel, this.handle, forward); 4067 } 4068 else 4069 { 4070 ctrltoplevel._selectChild(this); 4071 } 4072 } 4073 else 4074 { 4075 focus(); // This must be a form so just focus it ? 4076 } 4077 } 4078 4079 4080 /// 4081 final void setBounds(int x, int y, int width, int height) 4082 { 4083 setBoundsCore(x, y, width, height, BoundsSpecified.ALL); 4084 } 4085 4086 /// ditto 4087 final void setBounds(int x, int y, int width, int height, BoundsSpecified specified) 4088 { 4089 setBoundsCore(x, y, width, height, specified); 4090 } 4091 4092 4093 override Dstring toString() 4094 { 4095 return text; 4096 } 4097 4098 4099 /// 4100 final void update() 4101 { 4102 if(!created) 4103 return; 4104 4105 UpdateWindow(hwnd); 4106 } 4107 4108 4109 /// 4110 // If mouseEnter, mouseHover and mouseLeave events are supported. 4111 // Returns true on Windows 95 with IE 5.5, Windows 98+ or Windows NT 4.0+. 4112 static @property bool supportsMouseTracking() // getter 4113 { 4114 return trackMouseEvent != null; 4115 } 4116 4117 4118 package final Rect _fetchBounds() 4119 { 4120 RECT r; 4121 GetWindowRect(hwnd, &r); 4122 HWND hwParent = GetParent(hwnd); 4123 if(hwParent && (_style() & WS_CHILD)) 4124 MapWindowPoints(HWND.init, hwParent, cast(POINT*)&r, 2); 4125 return Rect(&r); 4126 } 4127 4128 4129 package final Size _fetchClientSize() 4130 { 4131 RECT r; 4132 GetClientRect(hwnd, &r); 4133 return Size(r.right, r.bottom); 4134 } 4135 4136 4137 deprecated protected void onInvalidated(InvalidateEventArgs iea) 4138 { 4139 //invalidated(this, iea); 4140 } 4141 4142 4143 /// 4144 protected void onPaint(PaintEventArgs pea) 4145 { 4146 paint(this, pea); 4147 } 4148 4149 4150 /// 4151 protected void onMove(EventArgs ea) 4152 { 4153 move(this, ea); 4154 } 4155 4156 4157 /+ 4158 protected void onLocationChanged(EventArgs ea) 4159 { 4160 locationChanged(this, ea); 4161 } 4162 +/ 4163 alias onMove onLocationChanged; 4164 4165 4166 /// 4167 protected void onResize(EventArgs ea) 4168 { 4169 resize(this, ea); 4170 } 4171 4172 4173 /+ 4174 protected void onSizeChanged(EventArgs ea) 4175 { 4176 sizeChanged(this, ea); 4177 } 4178 +/ 4179 alias onResize onSizeChanged; 4180 4181 4182 /+ 4183 // /// 4184 // Allows comparing before and after dimensions, and also allows modifying the new dimensions. 4185 deprecated protected void onBeforeResize(BeforeResizeEventArgs ea) 4186 { 4187 } 4188 +/ 4189 4190 4191 /// 4192 protected void onMouseEnter(MouseEventArgs mea) 4193 { 4194 mouseEnter(this, mea); 4195 } 4196 4197 4198 /// 4199 protected void onMouseMove(MouseEventArgs mea) 4200 { 4201 mouseMove(this, mea); 4202 } 4203 4204 4205 /// 4206 protected void onKeyDown(KeyEventArgs kea) 4207 { 4208 keyDown(this, kea); 4209 } 4210 4211 4212 /// 4213 protected void onKeyPress(KeyPressEventArgs kea) 4214 { 4215 keyPress(this, kea); 4216 } 4217 4218 4219 /// 4220 protected void onKeyUp(KeyEventArgs kea) 4221 { 4222 keyUp(this, kea); 4223 } 4224 4225 4226 /// 4227 protected void onMouseWheel(MouseEventArgs mea) 4228 { 4229 mouseWheel(this, mea); 4230 } 4231 4232 4233 /// 4234 protected void onMouseHover(MouseEventArgs mea) 4235 { 4236 mouseHover(this, mea); 4237 } 4238 4239 4240 /// 4241 protected void onMouseLeave(MouseEventArgs mea) 4242 { 4243 mouseLeave(this, mea); 4244 } 4245 4246 4247 /// 4248 protected void onMouseDown(MouseEventArgs mea) 4249 { 4250 mouseDown(this, mea); 4251 } 4252 4253 4254 /// 4255 protected void onMouseUp(MouseEventArgs mea) 4256 { 4257 mouseUp(this, mea); 4258 } 4259 4260 4261 /// 4262 protected void onClick(EventArgs ea) 4263 { 4264 click(this, ea); 4265 } 4266 4267 4268 /// 4269 protected void onDoubleClick(EventArgs ea) 4270 { 4271 doubleClick(this, ea); 4272 } 4273 4274 4275 /// 4276 protected void onGotFocus(EventArgs ea) 4277 { 4278 gotFocus(this, ea); 4279 } 4280 4281 4282 /+ 4283 deprecated protected void onEnter(EventArgs ea) 4284 { 4285 //enter(this, ea); 4286 } 4287 4288 4289 deprecated protected void onLeave(EventArgs ea) 4290 { 4291 //leave(this, ea); 4292 } 4293 4294 4295 deprecated protected void onValidated(EventArgs ea) 4296 { 4297 //validated(this, ea); 4298 } 4299 4300 4301 deprecated protected void onValidating(CancelEventArgs cea) 4302 { 4303 /+ 4304 foreach(CancelEventHandler.Handler handler; validating.handlers()) 4305 { 4306 handler(this, cea); 4307 4308 if(cea.cancel) 4309 return; // Not validated. 4310 } 4311 4312 onValidated(EventArgs.empty); 4313 +/ 4314 } 4315 +/ 4316 4317 4318 /// 4319 protected void onLostFocus(EventArgs ea) 4320 { 4321 lostFocus(this, ea); 4322 } 4323 4324 4325 /// 4326 protected void onEnabledChanged(EventArgs ea) 4327 { 4328 enabledChanged(this, ea); 4329 } 4330 4331 4332 /// 4333 protected void onTextChanged(EventArgs ea) 4334 { 4335 textChanged(this, ea); 4336 } 4337 4338 4339 private void _propagateFontAmbience() 4340 { 4341 Font fon; 4342 fon = font; 4343 4344 4345 void pa(Control pc) 4346 { 4347 foreach(Control ctrl; pc.ccollection) 4348 { 4349 if(!ctrl.wfont) // If default. 4350 { 4351 if(fon is ctrl.font) // If same default. 4352 { 4353 if(ctrl.isHandleCreated) 4354 SendMessageA(ctrl.hwnd, WM_SETFONT, cast(WPARAM)fon.handle, MAKELPARAM(true, 0)); 4355 ctrl.onFontChanged(EventArgs.empty); 4356 4357 pa(ctrl); // Recursive. 4358 } 4359 } 4360 } 4361 } 4362 4363 4364 pa(this); 4365 } 4366 4367 4368 /// 4369 protected void onFontChanged(EventArgs ea) 4370 { 4371 debug(EVENT_PRINT) 4372 { 4373 cprintf("{ Event: onFontChanged - Control %.*s }\n", name); 4374 } 4375 4376 fontChanged(this, ea); 4377 } 4378 4379 4380 /// 4381 protected void onRightToLeftChanged(EventArgs ea) 4382 { 4383 debug(EVENT_PRINT) 4384 { 4385 cprintf("{ Event: onRightToLeftChanged - Control %.*s }\n", name); 4386 } 4387 4388 rightToLeftChanged(this, ea); 4389 } 4390 4391 4392 /// 4393 protected void onVisibleChanged(EventArgs ea) 4394 { 4395 if(wparent) 4396 { 4397 wparent.vchanged(); 4398 suspendLayout(); // Note: exception could cause failure to restore. 4399 wparent.alayout(this); 4400 resumeLayout(false); 4401 } 4402 if(visible) 4403 alayout(this); 4404 4405 visibleChanged(this, ea); 4406 4407 if(visible) 4408 { 4409 // If no focus or the focused control is hidden, try to select something... 4410 HWND hwfocus = GetFocus(); 4411 if(!hwfocus 4412 || (hwfocus == hwnd && !getStyle(ControlStyles.SELECTABLE)) 4413 || !IsWindowVisible(hwfocus)) 4414 { 4415 selectNextControl(null, true, true, true, false); 4416 } 4417 } 4418 } 4419 4420 4421 /// 4422 protected void onHelpRequested(HelpEventArgs hea) 4423 { 4424 debug(EVENT_PRINT) 4425 { 4426 cprintf("{ Event: onHelpRequested - Control %.*s }\n", name); 4427 } 4428 4429 helpRequested(this, hea); 4430 } 4431 4432 4433 /// 4434 protected void onSystemColorsChanged(EventArgs ea) 4435 { 4436 debug(EVENT_PRINT) 4437 { 4438 cprintf("{ Event: onSystemColorsChanged - Control %.*s }\n", name); 4439 } 4440 4441 systemColorsChanged(this, ea); 4442 } 4443 4444 4445 /// 4446 protected void onHandleCreated(EventArgs ea) 4447 { 4448 if(!(cbits & CBits.VSTYLE)) 4449 _disableVisualStyle(); 4450 4451 Font fon; 4452 fon = font; 4453 if(fon) 4454 SendMessageA(hwnd, WM_SETFONT, cast(WPARAM)fon.handle, 0); 4455 4456 if(wregion) 4457 { 4458 // Need to make a copy of the region. 4459 SetWindowRgn(hwnd, dupHrgn(wregion.handle), true); 4460 } 4461 4462 version(DFL_NO_DRAG_DROP) {} else 4463 { 4464 if(droptarget) 4465 { 4466 if(S_OK != RegisterDragDrop(hwnd, droptarget)) 4467 { 4468 droptarget = null; 4469 throw new DflException("Unable to register drag-drop"); 4470 } 4471 } 4472 } 4473 4474 debug 4475 { 4476 _handlecreated = true; 4477 } 4478 } 4479 4480 4481 /// 4482 protected void onHandleDestroyed(EventArgs ea) 4483 { 4484 handleDestroyed(this, ea); 4485 } 4486 4487 4488 /// 4489 protected void onPaintBackground(PaintEventArgs pea) 4490 { 4491 RECT rect; 4492 pea.clipRectangle.getRect(&rect); 4493 FillRect(pea.graphics.handle, &rect, hbrBg); 4494 } 4495 4496 4497 private static MouseButtons wparamMouseButtons(WPARAM wparam) 4498 { 4499 MouseButtons result; 4500 if(wparam & MK_LBUTTON) 4501 result |= MouseButtons.LEFT; 4502 if(wparam & MK_RBUTTON) 4503 result |= MouseButtons.RIGHT; 4504 if(wparam & MK_MBUTTON) 4505 result |= MouseButtons.MIDDLE; 4506 return result; 4507 } 4508 4509 4510 package final void prepareDc(HDC hdc) 4511 { 4512 //SetBkMode(hdc, TRANSPARENT); // ? 4513 //SetBkMode(hdc, OPAQUE); // ? 4514 SetBkColor(hdc, backColor.toRgb()); 4515 SetTextColor(hdc, foreColor.toRgb()); 4516 } 4517 4518 4519 // Message copy so it cannot be modified. 4520 deprecated protected void onNotifyMessage(Message msg) 4521 { 4522 } 4523 4524 4525 /+ 4526 /+package+/ LRESULT customMsg(ref CustomMsg msg) // package 4527 { 4528 return 0; 4529 } 4530 +/ 4531 4532 4533 /// 4534 protected void onReflectedMessage(ref Message m) 4535 { 4536 switch(m.msg) 4537 { 4538 case WM_CTLCOLORSTATIC: 4539 case WM_CTLCOLORLISTBOX: 4540 case WM_CTLCOLOREDIT: 4541 case WM_CTLCOLORSCROLLBAR: 4542 case WM_CTLCOLORBTN: 4543 //case WM_CTLCOLORDLG: // ? 4544 //case 0x0019: //WM_CTLCOLOR; obsolete. 4545 prepareDc(cast(HDC)m.wParam); 4546 //assert(GetObjectA(hbrBg, 0, null)); 4547 m.result = cast(LRESULT)hbrBg; 4548 break; 4549 4550 default: 4551 } 4552 } 4553 4554 4555 // ChildWindowFromPoint includes both hidden and disabled. 4556 // This includes disabled windows, but not hidden. 4557 // Here is a point in this control, see if it's over a visible child. 4558 // Returns null if not even in this control's client. 4559 final HWND pointOverVisibleChild(Point pt) // package 4560 { 4561 if(pt.x < 0 || pt.y < 0) 4562 return HWND.init; 4563 if(pt.x > wclientsz.width || pt.y > wclientsz.height) 4564 return HWND.init; 4565 4566 // Note: doesn't include non-DFL windows... TO-DO: fix. 4567 foreach(Control ctrl; ccollection) 4568 { 4569 if(!ctrl.visible) 4570 continue; 4571 if(!ctrl.isHandleCreated) // Shouldn't.. 4572 continue; 4573 if(ctrl.bounds.contains(pt)) 4574 return ctrl.hwnd; 4575 } 4576 4577 return hwnd; // Just over this control. 4578 } 4579 4580 4581 version(_DFL_WINDOWS_HUNG_WORKAROUND) 4582 { 4583 DWORD ldlgcode = 0; 4584 } 4585 4586 4587 /// 4588 protected void wndProc(ref Message msg) 4589 { 4590 //if(ctrlStyle & ControlStyles.ENABLE_NOTIFY_MESSAGE) 4591 // onNotifyMessage(msg); 4592 4593 switch(msg.msg) 4594 { 4595 case WM_PAINT: 4596 { 4597 // This can't be done in BeginPaint() becuase part might get 4598 // validated during this event ? 4599 //RECT uprect; 4600 //GetUpdateRect(hwnd, &uprect, true); 4601 //onInvalidated(new InvalidateEventArgs(Rect(&uprect))); 4602 4603 PAINTSTRUCT ps; 4604 BeginPaint(msg.hWnd, &ps); 4605 try 4606 { 4607 //onInvalidated(new InvalidateEventArgs(Rect(&uprect))); 4608 4609 scope PaintEventArgs pea = new PaintEventArgs(new Graphics(ps.hdc, false), Rect(&ps.rcPaint)); 4610 4611 // Probably because ControlStyles.ALL_PAINTING_IN_WM_PAINT. 4612 if(ps.fErase) 4613 { 4614 prepareDc(ps.hdc); 4615 onPaintBackground(pea); 4616 } 4617 4618 prepareDc(ps.hdc); 4619 onPaint(pea); 4620 } 4621 finally 4622 { 4623 EndPaint(hwnd, &ps); 4624 } 4625 } 4626 return; 4627 4628 case WM_ERASEBKGND: 4629 if(ctrlStyle & ControlStyles.OPAQUE) 4630 { 4631 msg.result = 1; // Erased. 4632 } 4633 else if(!(ctrlStyle & ControlStyles.ALL_PAINTING_IN_WM_PAINT)) 4634 { 4635 RECT uprect; 4636 /+ 4637 GetUpdateRect(hwnd, &uprect, false); 4638 +/ 4639 uprect.left = 0; 4640 uprect.top = 0; 4641 uprect.right = clientSize.width; 4642 uprect.bottom = clientSize.height; 4643 4644 prepareDc(cast(HDC)msg.wParam); 4645 scope PaintEventArgs pea = new PaintEventArgs(new Graphics(cast(HDC)msg.wParam, false), Rect(&uprect)); 4646 onPaintBackground(pea); 4647 msg.result = 1; // Erased. 4648 } 4649 return; 4650 4651 case WM_PRINTCLIENT: 4652 prepareDc(cast(HDC)msg.wParam); 4653 scope PaintEventArgs pea = new PaintEventArgs(new Graphics(cast(HDC)msg.wParam, false), Rect(Point(0, 0), wclientsz)); 4654 onPaint(pea); 4655 return; 4656 4657 case WM_CTLCOLORSTATIC: 4658 case WM_CTLCOLORLISTBOX: 4659 case WM_CTLCOLOREDIT: 4660 case WM_CTLCOLORSCROLLBAR: 4661 case WM_CTLCOLORBTN: 4662 //case WM_CTLCOLORDLG: // ? 4663 //case 0x0019: //WM_CTLCOLOR; obsolete. 4664 { 4665 Control ctrl = fromChildHandle(cast(HWND)msg.lParam); 4666 if(ctrl) 4667 { 4668 //ctrl.prepareDc(cast(HDC)msg.wParam); 4669 //msg.result = cast(LRESULT)ctrl.hbrBg; 4670 ctrl.onReflectedMessage(msg); 4671 return; 4672 } 4673 } 4674 break; 4675 4676 case WM_WINDOWPOSCHANGED: 4677 { 4678 WINDOWPOS* wp = cast(WINDOWPOS*)msg.lParam; 4679 bool needLayout = false; 4680 4681 //if(!wp.hwndInsertAfter) 4682 // wp.flags |= SWP_NOZORDER; // ? 4683 4684 bool didvis = false; 4685 if(wp.flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) 4686 { 4687 needLayout = true; // Only if not didvis / if not recreating. 4688 if(!recreatingHandle) // Note: suppresses onVisibleChanged 4689 { 4690 if(wp.flags & SWP_HIDEWINDOW) // Hiding. 4691 _clicking = false; 4692 onVisibleChanged(EventArgs.empty); 4693 didvis = true; 4694 //break; // Showing min/max includes other flags. 4695 } 4696 } 4697 4698 if(!(wp.flags & SWP_NOZORDER) /+ || (wp.flags & SWP_SHOWWINDOW) +/) 4699 { 4700 if(wparent) 4701 wparent.vchanged(); 4702 } 4703 4704 if(!(wp.flags & SWP_NOMOVE)) 4705 { 4706 onMove(EventArgs.empty); 4707 } 4708 4709 if(!(wp.flags & SWP_NOSIZE)) 4710 { 4711 if(szdraw) 4712 invalidate(true); 4713 4714 onResize(EventArgs.empty); 4715 4716 needLayout = true; 4717 } 4718 4719 // Frame change results in a new client size. 4720 if(wp.flags & SWP_FRAMECHANGED) 4721 { 4722 if(szdraw) 4723 invalidate(true); 4724 4725 needLayout = true; 4726 } 4727 4728 if(!didvis) // onVisibleChanged already triggers layout. 4729 { 4730 if(/+ (wp.flags & SWP_SHOWWINDOW) || +/ !(wp.flags & SWP_NOSIZE) || 4731 !(wp.flags & SWP_NOZORDER)) // z-order determines what is positioned first. 4732 { 4733 suspendLayout(); // Note: exception could cause failure to restore. 4734 if(wparent) 4735 wparent.alayout(this); 4736 resumeLayout(false); 4737 needLayout = true; 4738 } 4739 4740 if(needLayout) 4741 { 4742 alayout(this); 4743 } 4744 } 4745 } 4746 break; 4747 4748 /+ 4749 case WM_WINDOWPOSCHANGING: 4750 { 4751 WINDOWPOS* wp = cast(WINDOWPOS*)msg.lParam; 4752 4753 /+ 4754 //if(!(wp.flags & SWP_NOSIZE)) 4755 if(width != wp.cx || height != wp.cy) 4756 { 4757 scope BeforeResizeEventArgs ea = new BeforeResizeEventArgs(wp.cx, wp.cy); 4758 onBeforeResize(ea); 4759 /+if(wp.cx == ea.width && wp.cy == ea.height) 4760 { 4761 wp.flags |= SWP_NOSIZE; 4762 } 4763 else+/ 4764 { 4765 wp.cx = ea.width; 4766 wp.cy = ea.height; 4767 } 4768 } 4769 +/ 4770 } 4771 break; 4772 +/ 4773 4774 case WM_MOUSEMOVE: 4775 if(_clicking) 4776 { 4777 if(!(msg.wParam & MK_LBUTTON)) 4778 _clicking = false; 4779 } 4780 4781 if(trackMouseEvent) // Requires Windows 95 with IE 5.5, 98 or NT4. 4782 { 4783 if(!menter) 4784 { 4785 menter = true; 4786 4787 POINT pt; 4788 GetCursorPos(&pt); 4789 MapWindowPoints(HWND.init, hwnd, &pt, 1); 4790 scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, pt.x, pt.y, 0); 4791 onMouseEnter(mea); 4792 4793 TRACKMOUSEEVENT tme; 4794 tme.cbSize = TRACKMOUSEEVENT.sizeof; 4795 tme.dwFlags = TME_HOVER | TME_LEAVE; 4796 tme.hwndTrack = msg.hWnd; 4797 tme.dwHoverTime = HOVER_DEFAULT; 4798 trackMouseEvent(&tme); 4799 } 4800 } 4801 4802 onMouseMove(new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0)); 4803 break; 4804 4805 case WM_SETCURSOR: 4806 // Just update it so that Control.defWndProc() can set it correctly. 4807 if(cast(HWND)msg.wParam == hwnd) 4808 { 4809 Cursor cur; 4810 cur = cursor; 4811 if(cur) 4812 { 4813 if(cast(HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR) != cur.handle) 4814 SetClassLongA(hwnd, GCL_HCURSOR, cast(LONG)cur.handle); 4815 } 4816 else 4817 { 4818 if(cast(HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR) != HCURSOR.init) 4819 SetClassLongA(hwnd, GCL_HCURSOR, cast(LONG)cast(HCURSOR)null); 4820 } 4821 Control.defWndProc(msg); 4822 return; 4823 } 4824 break; 4825 4826 /+ 4827 case WM_NEXTDLGCTL: 4828 if(!LOWORD(msg.lParam)) 4829 { 4830 select(true, msg.wParam != 0); 4831 return; 4832 } 4833 break; 4834 +/ 4835 4836 case WM_KEYDOWN: 4837 case WM_KEYUP: 4838 case WM_CHAR: 4839 case WM_SYSKEYDOWN: 4840 case WM_SYSKEYUP: 4841 case WM_SYSCHAR: 4842 //case WM_IMECHAR: 4843 /+ 4844 if(processKeyEventArgs(msg)) 4845 { 4846 // The key was processed. 4847 msg.result = 0; 4848 return; 4849 } 4850 msg.result = 1; // The key was not processed. 4851 break; 4852 +/ 4853 msg.result = !processKeyEventArgs(msg); 4854 return; 4855 4856 case WM_MOUSEWHEEL: // Requires Windows 98 or NT4. 4857 { 4858 scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(LOWORD(msg.wParam)), 0, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), cast(short)HIWORD(msg.wParam)); 4859 onMouseWheel(mea); 4860 } 4861 break; 4862 4863 case WM_MOUSEHOVER: // Requires Windows 95 with IE 5.5, 98 or NT4. 4864 { 4865 scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 4866 onMouseHover(mea); 4867 } 4868 break; 4869 4870 case WM_MOUSELEAVE: // Requires Windows 95 with IE 5.5, 98 or NT4. 4871 { 4872 menter = false; 4873 4874 POINT pt; 4875 GetCursorPos(&pt); 4876 MapWindowPoints(HWND.init, hwnd, &pt, 1); 4877 scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, pt.x, pt.y, 0); 4878 onMouseLeave(mea); 4879 } 4880 break; 4881 4882 case WM_LBUTTONDOWN: 4883 { 4884 _clicking = true; 4885 4886 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 4887 onMouseDown(mea); 4888 4889 //if(ctrlStyle & ControlStyles.SELECTABLE) 4890 // SetFocus(hwnd); // No, this goofs up stuff, including the ComboBox dropdown. 4891 } 4892 break; 4893 4894 case WM_RBUTTONDOWN: 4895 { 4896 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 4897 onMouseDown(mea); 4898 } 4899 break; 4900 4901 case WM_MBUTTONDOWN: 4902 { 4903 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 4904 onMouseDown(mea); 4905 } 4906 break; 4907 4908 case WM_LBUTTONUP: 4909 { 4910 if(msg.lParam == -1) 4911 break; 4912 4913 // Use temp in case of exception. 4914 bool wasClicking = _clicking; 4915 _clicking = false; 4916 4917 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 4918 onMouseUp(mea); 4919 4920 if(wasClicking && (ctrlStyle & ControlStyles.STANDARD_CLICK)) 4921 { 4922 // See if the mouse up was over the control. 4923 if(Rect(0, 0, wclientsz.width, wclientsz.height).contains(mea.x, mea.y)) 4924 { 4925 // Now make sure there's no child in the way. 4926 //if(ChildWindowFromPoint(hwnd, Point(mea.x, mea.y).point) == hwnd) // Includes hidden windows. 4927 if(pointOverVisibleChild(Point(mea.x, mea.y)) == hwnd) 4928 onClick(EventArgs.empty); 4929 } 4930 } 4931 } 4932 break; 4933 4934 version(CUSTOM_MSG_HOOK) 4935 {} 4936 else 4937 { 4938 case WM_DRAWITEM: 4939 { 4940 Control ctrl; 4941 4942 DRAWITEMSTRUCT* dis = cast(DRAWITEMSTRUCT*)msg.lParam; 4943 if(dis.CtlType == ODT_MENU) 4944 { 4945 // dis.hwndItem is the HMENU. 4946 } 4947 else 4948 { 4949 ctrl = Control.fromChildHandle(dis.hwndItem); 4950 if(ctrl) 4951 { 4952 //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg)); 4953 ctrl.onReflectedMessage(msg); 4954 return; 4955 } 4956 } 4957 } 4958 break; 4959 4960 case WM_MEASUREITEM: 4961 { 4962 Control ctrl; 4963 4964 MEASUREITEMSTRUCT* mis = cast(MEASUREITEMSTRUCT*)msg.lParam; 4965 if(!(mis.CtlType == ODT_MENU)) 4966 { 4967 ctrl = Control.fromChildHandle(cast(HWND)mis.CtlID); 4968 if(ctrl) 4969 { 4970 //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg)); 4971 ctrl.onReflectedMessage(msg); 4972 return; 4973 } 4974 } 4975 } 4976 break; 4977 4978 case WM_COMMAND: 4979 { 4980 /+ 4981 switch(LOWORD(msg.wParam)) 4982 { 4983 case IDOK: 4984 case IDCANCEL: 4985 if(parent) 4986 { 4987 parent.wndProc(msg); 4988 } 4989 //break; 4990 return; // ? 4991 4992 default: 4993 } 4994 +/ 4995 4996 Control ctrl; 4997 4998 ctrl = Control.fromChildHandle(cast(HWND)msg.lParam); 4999 if(ctrl) 5000 { 5001 //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg)); 5002 ctrl.onReflectedMessage(msg); 5003 return; 5004 } 5005 else 5006 { 5007 version(DFL_NO_MENUS) 5008 { 5009 } 5010 else 5011 { 5012 MenuItem m; 5013 5014 m = cast(MenuItem)Application.lookupMenuID(LOWORD(msg.wParam)); 5015 if(m) 5016 { 5017 //msg.result = m.customMsg(*(cast(CustomMsg*)&msg)); 5018 m._reflectMenu(msg); 5019 //return; // ? 5020 } 5021 } 5022 } 5023 } 5024 break; 5025 5026 case WM_NOTIFY: 5027 { 5028 Control ctrl; 5029 NMHDR* nmh; 5030 nmh = cast(NMHDR*)msg.lParam; 5031 5032 ctrl = Control.fromChildHandle(nmh.hwndFrom); 5033 if(ctrl) 5034 { 5035 //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg)); 5036 ctrl.onReflectedMessage(msg); 5037 return; 5038 } 5039 } 5040 break; 5041 5042 version(DFL_NO_MENUS) 5043 { 5044 } 5045 else 5046 { 5047 case WM_MENUSELECT: 5048 { 5049 UINT mflags; 5050 UINT uitem; 5051 int mid; 5052 MenuItem m; 5053 5054 mflags = HIWORD(msg.wParam); 5055 uitem = LOWORD(msg.wParam); // Depends on the flags. 5056 5057 if(mflags & MF_SYSMENU) 5058 break; 5059 5060 if(mflags & MF_POPUP) 5061 { 5062 // -uitem- is an index. 5063 mid = GetMenuItemID(cast(HMENU)msg.lParam, uitem); 5064 } 5065 else 5066 { 5067 // -uitem- is the item identifier. 5068 mid = uitem; 5069 } 5070 5071 m = cast(MenuItem)Application.lookupMenuID(mid); 5072 if(m) 5073 { 5074 //msg.result = m.customMsg(*(cast(CustomMsg*)&msg)); 5075 m._reflectMenu(msg); 5076 //return; 5077 } 5078 } 5079 break; 5080 5081 case WM_INITMENUPOPUP: 5082 if(HIWORD(msg.lParam)) 5083 { 5084 // System menu. 5085 } 5086 else 5087 { 5088 MenuItem m; 5089 5090 //m = cast(MenuItem)Application.lookupMenuID(GetMenuItemID(cast(HMENU)msg.wParam, LOWORD(msg.lParam))); 5091 m = cast(MenuItem)Application.lookupMenu(cast(HMENU)msg.wParam); 5092 if(m) 5093 { 5094 //msg.result = m.customMsg(*(cast(CustomMsg*)&msg)); 5095 m._reflectMenu(msg); 5096 //return; 5097 } 5098 } 5099 break; 5100 5101 case WM_INITMENU: 5102 { 5103 ContextMenu m; 5104 5105 m = cast(ContextMenu)Application.lookupMenu(cast(HMENU)msg.wParam); 5106 if(m) 5107 { 5108 //msg.result = m.customMsg(*(cast(CustomMsg*)&msg)); 5109 m._reflectMenu(msg); 5110 //return; 5111 } 5112 } 5113 break; 5114 } 5115 } 5116 5117 case WM_RBUTTONUP: 5118 { 5119 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 5120 onMouseUp(mea); 5121 } 5122 break; 5123 5124 case WM_MBUTTONUP: 5125 { 5126 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 5127 onMouseUp(mea); 5128 } 5129 break; 5130 5131 case WM_LBUTTONDBLCLK: 5132 { 5133 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 2, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 5134 onMouseDown(mea); 5135 5136 if((ctrlStyle & (ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK)) 5137 == (ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK)) 5138 { 5139 onDoubleClick(EventArgs.empty); 5140 } 5141 } 5142 break; 5143 5144 case WM_RBUTTONDBLCLK: 5145 { 5146 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT, 2, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 5147 onMouseDown(mea); 5148 } 5149 break; 5150 5151 case WM_MBUTTONDBLCLK: 5152 { 5153 scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE, 2, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0); 5154 onMouseDown(mea); 5155 } 5156 break; 5157 5158 case WM_SETFOCUS: 5159 _wmSetFocus(); 5160 // defWndProc* Form focuses a child. 5161 break; 5162 5163 case WM_KILLFOCUS: 5164 _wmKillFocus(); 5165 break; 5166 5167 case WM_ENABLE: 5168 onEnabledChanged(EventArgs.empty); 5169 5170 // defWndProc* 5171 break; 5172 5173 /+ 5174 case WM_NEXTDLGCTL: 5175 if(msg.wParam && !LOWORD(msg.lParam)) 5176 { 5177 HWND hwf; 5178 hwf = GetFocus(); 5179 if(hwf) 5180 { 5181 Control hwc; 5182 hwc = Control.fromHandle(hwf); 5183 if(hwc) 5184 { 5185 if(hwc._rtype() & 0x20) // TabControl 5186 { 5187 hwf = GetWindow(hwf, GW_CHILD); 5188 if(hwf) 5189 { 5190 // Can't do this because it could be modifying someone else's memory. 5191 //msg.wParam = cast(WPARAM)hwf; 5192 //msg.lParam = MAKELPARAM(1, 0); 5193 msg.result = DefWindowProcA(msg.hWnd, WM_NEXTDLGCTL, cast(WPARAM)hwf, MAKELPARAM(TRUE, 0)); 5194 return; 5195 } 5196 } 5197 } 5198 } 5199 } 5200 break; 5201 +/ 5202 5203 case WM_SETTEXT: 5204 defWndProc(msg); 5205 5206 // Need to fetch it because cast(char*)lparam isn't always accessible ? 5207 // Should this go in _wndProc()? Need to defWndProc() first ? 5208 if(ctrlStyle & ControlStyles.CACHE_TEXT) 5209 wtext = _fetchText(); 5210 5211 onTextChanged(EventArgs.empty); 5212 return; 5213 5214 case WM_SETFONT: 5215 // Don't replace -wfont- if it's the same one, beacuse the old Font 5216 // object will get garbage collected and probably delete the HFONT. 5217 5218 //onFontChanged(EventArgs.empty); 5219 5220 // defWndProc* 5221 return; 5222 5223 /+ 5224 case WM_STYLECHANGED: 5225 { 5226 //defWndProc(msg); 5227 5228 STYLESTRUCT* ss = cast(STYLESTRUCT*)msg.lParam; 5229 DWORD changed = ss.styleOld ^ ss.styleNew; 5230 5231 if(msg.wParam == GWL_EXSTYLE) 5232 { 5233 //if(changed & WS_EX_RTLREADING) 5234 // onRightToLeftChanged(EventArgs.empty); 5235 } 5236 } 5237 break; 5238 +/ 5239 5240 case WM_ACTIVATE: 5241 switch(LOWORD(msg.wParam)) 5242 { 5243 case WA_INACTIVE: 5244 _clicking = false; 5245 break; 5246 5247 default: 5248 } 5249 break; 5250 5251 version(DFL_NO_MENUS) 5252 { 5253 } 5254 else 5255 { 5256 case WM_CONTEXTMENU: 5257 if(hwnd == cast(HWND)msg.wParam) 5258 { 5259 if(cmenu) 5260 { 5261 // Shift+F10 causes xPos and yPos to be -1. 5262 5263 Point point; 5264 5265 if(msg.lParam == -1) 5266 point = pointToScreen(Point(0, 0)); 5267 else 5268 point = Point(cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam)); 5269 5270 SetFocus(handle); // ? 5271 cmenu.show(this, point); 5272 5273 return; 5274 } 5275 } 5276 break; 5277 } 5278 5279 case WM_HELP: 5280 { 5281 HELPINFO* hi = cast(HELPINFO*)msg.lParam; 5282 5283 scope HelpEventArgs hea = new HelpEventArgs(Point(hi.MousePos.x, hi.MousePos.y)); 5284 onHelpRequested(hea); 5285 if(hea.handled) 5286 { 5287 msg.result = TRUE; 5288 return; 5289 } 5290 } 5291 break; 5292 5293 case WM_SYSCOLORCHANGE: 5294 onSystemColorsChanged(EventArgs.empty); 5295 5296 // Need to send the message to children for some common controls to update properly. 5297 foreach(Control ctrl; ccollection) 5298 { 5299 SendMessageA(ctrl.handle, WM_SYSCOLORCHANGE, msg.wParam, msg.lParam); 5300 } 5301 break; 5302 5303 case WM_SETTINGCHANGE: 5304 // Send the message to children. 5305 foreach(Control ctrl; ccollection) 5306 { 5307 SendMessageA(ctrl.handle, WM_SETTINGCHANGE, msg.wParam, msg.lParam); 5308 } 5309 break; 5310 5311 case WM_PALETTECHANGED: 5312 /+ 5313 if(cast(HWND)msg.wParam != hwnd) 5314 { 5315 // Realize palette. 5316 } 5317 +/ 5318 5319 // Send the message to children. 5320 foreach(Control ctrl; ccollection) 5321 { 5322 SendMessageA(ctrl.handle, WM_PALETTECHANGED, msg.wParam, msg.lParam); 5323 } 5324 break; 5325 5326 //case WM_QUERYNEWPALETTE: // Send this message to children ? 5327 5328 /+ 5329 // Moved this stuff to -parent-. 5330 case WM_PARENTNOTIFY: 5331 switch(LOWORD(msg.wParam)) 5332 { 5333 case WM_DESTROY: 5334 Control ctrl = fromChildHandle(cast(HWND)msg.lParam); 5335 if(ctrl) 5336 { 5337 _ctrlremoved(new ControlEventArgs(ctrl)); 5338 5339 // ? 5340 vchanged(); 5341 //alayout(ctrl); // This is already being called from somewhere else.. 5342 } 5343 break; 5344 5345 /+ 5346 case WM_CREATE: 5347 initLayout(); 5348 break; 5349 +/ 5350 5351 default: 5352 } 5353 break; 5354 +/ 5355 5356 case WM_CREATE: 5357 /+ 5358 if(wparent) 5359 initLayout(); // ? 5360 +/ 5361 if(cbits & CBits.NEED_INIT_LAYOUT) 5362 { 5363 if(visible) 5364 { 5365 if(wparent) 5366 { 5367 wparent.vchanged(); 5368 suspendLayout(); // Note: exception could cause failure to restore. 5369 wparent.alayout(this); 5370 resumeLayout(false); 5371 } 5372 alayout(this); 5373 } 5374 } 5375 break; 5376 5377 case WM_DESTROY: 5378 onHandleDestroyed(EventArgs.empty); 5379 break; 5380 5381 case WM_GETDLGCODE: 5382 { 5383 version(_DFL_WINDOWS_HUNG_WORKAROUND) 5384 { 5385 /+ 5386 if(ctrlStyle & ControlStyles.CONTAINER_CONTROL) 5387 { 5388 if(!(_exStyle & WS_EX_CONTROLPARENT)) 5389 assert(0); 5390 } 5391 +/ 5392 5393 DWORD dw; 5394 dw = GetTickCount(); 5395 if(ldlgcode < dw - 1020) 5396 { 5397 ldlgcode = dw - 1000; 5398 } 5399 else 5400 { 5401 ldlgcode += 50; 5402 if(ldlgcode > dw) 5403 { 5404 // Probably a problem with WS_EX_CONTROLPARENT and WS_TABSTOP. 5405 if(ldlgcode >= ldlgcode.max - 10_000) 5406 { 5407 ldlgcode = 0; 5408 throw new WindowsHungDflException("Windows hung"); 5409 } 5410 //msg.result |= 0x0004 | 0x0002 | 0x0001; //DLGC_WANTALLKEYS | DLGC_WANTTAB | DLGC_WANTARROWS; 5411 ldlgcode = ldlgcode.max - 10_000; 5412 return; 5413 } 5414 } 5415 } 5416 5417 /+ 5418 if(msg.lParam) 5419 { 5420 Message m; 5421 m._winMsg = *cast(MSG*)msg.lParam; 5422 if(processKeyEventArgs(m)) 5423 return; 5424 } 5425 +/ 5426 5427 defWndProc(msg); 5428 5429 if(ctrlStyle & ControlStyles.WANT_ALL_KEYS) 5430 msg.result |= DLGC_WANTALLKEYS; 5431 5432 // Only want chars if ALT isn't down, because it would break mnemonics. 5433 if(!(GetKeyState(VK_MENU) & 0x8000)) 5434 msg.result |= DLGC_WANTCHARS; 5435 5436 } 5437 return; 5438 5439 case WM_CLOSE: 5440 /+{ 5441 if(parent) 5442 { 5443 Message mp; 5444 mp = msg; 5445 mp.hWnd = parent.handle; 5446 parent.wndProc(mp); // Pass to parent so it can decide what to do. 5447 } 5448 }+/ 5449 return; // Prevent defWndProc from destroying the window! 5450 5451 case 0: // WM_NULL 5452 // Don't confuse with failed RegisterWindowMessage(). 5453 break; 5454 5455 default: 5456 //defWndProc(msg); 5457 version(DFL_NO_WM_GETCONTROLNAME) 5458 { 5459 } 5460 else 5461 { 5462 if(msg.msg == wmGetControlName) 5463 { 5464 //cprintf("WM_GETCONTROLNAME: %.*s; wparam: %d\n", cast(uint)name.length, name.ptr, msg.wParam); 5465 if(msg.wParam && this.name.length) 5466 { 5467 OSVERSIONINFOA osver; 5468 osver.dwOSVersionInfoSize = OSVERSIONINFOA.sizeof; 5469 if(GetVersionExA(&osver)) 5470 { 5471 try 5472 { 5473 if(osver.dwPlatformId <= VER_PLATFORM_WIN32_WINDOWS) 5474 { 5475 version(DFL_UNICODE) 5476 { 5477 } 5478 else 5479 { 5480 // ANSI. 5481 Dstring ansi; 5482 ansi = dfl.internal.utf.toAnsi(this.name); 5483 if(msg.wParam <= ansi.length) 5484 ansi = ansi[0 .. msg.wParam - 1]; 5485 (cast(char*)msg.lParam)[0 .. ansi.length] = ansi[]; 5486 (cast(char*)msg.lParam)[ansi.length] = 0; 5487 msg.result = ansi.length + 1; 5488 } 5489 } 5490 else 5491 { 5492 // Unicode. 5493 Dwstring uni; 5494 uni = dfl.internal.utf.toUnicode(this.name); 5495 if(msg.wParam <= uni.length) 5496 uni = uni[0 .. msg.wParam - 1]; 5497 (cast(wchar*)msg.lParam)[0 .. uni.length] = uni[]; 5498 (cast(wchar*)msg.lParam)[uni.length] = 0; 5499 msg.result = uni.length + 1; 5500 } 5501 } 5502 catch 5503 { 5504 } 5505 return; 5506 } 5507 } 5508 } 5509 } 5510 } 5511 5512 defWndProc(msg); 5513 5514 if(msg.msg == WM_CREATE) 5515 { 5516 EventArgs ea; 5517 ea = EventArgs.empty; 5518 onHandleCreated(ea); 5519 5520 debug 5521 { 5522 assert(_handlecreated, "If overriding onHandleCreated(), be sure to call super.onHandleCreated()!"); 5523 } 5524 handleCreated(this, ea); 5525 debug 5526 { 5527 _handlecreated = false; // Reset. 5528 } 5529 } 5530 } 5531 5532 5533 package final void _wmSetFocus() 5534 { 5535 //onEnter(EventArgs.empty); 5536 5537 onGotFocus(EventArgs.empty); 5538 5539 // defWndProc* Form focuses a child. 5540 } 5541 5542 5543 package final void _wmKillFocus() 5544 { 5545 _clicking = false; 5546 5547 //onLeave(EventArgs.empty); 5548 5549 //if(cvalidation) 5550 // onValidating(new CancelEventArgs); 5551 5552 onLostFocus(EventArgs.empty); 5553 } 5554 5555 5556 /// 5557 protected void defWndProc(ref Message msg) 5558 { 5559 //msg.result = DefWindowProcA(msg.hWnd, msg.msg, msg.wParam, msg.lParam); 5560 msg.result = dfl.internal.utf.defWindowProc(msg.hWnd, msg.msg, msg.wParam, msg.lParam); 5561 } 5562 5563 5564 // Always called right when destroyed, before doing anything else. 5565 // hwnd is cleared after this step. 5566 void _destroying() // package 5567 { 5568 //wparent = null; // ? 5569 } 5570 5571 5572 // This function must be called FIRST for EVERY message to this 5573 // window in order to keep the correct window state. 5574 // This function must not throw exceptions. 5575 package final void mustWndProc(ref Message msg) 5576 { 5577 if(needCalcSize) 5578 { 5579 needCalcSize = false; 5580 RECT crect; 5581 GetClientRect(msg.hWnd, &crect); 5582 wclientsz.width = crect.right; 5583 wclientsz.height = crect.bottom; 5584 } 5585 5586 switch(msg.msg) 5587 { 5588 case WM_NCCALCSIZE: 5589 needCalcSize = true; 5590 break; 5591 5592 case WM_WINDOWPOSCHANGED: 5593 { 5594 WINDOWPOS* wp = cast(WINDOWPOS*)msg.lParam; 5595 5596 if(!recreatingHandle) 5597 { 5598 //wstyle = GetWindowLongA(hwnd, GWL_STYLE); // ..WM_SHOWWINDOW. 5599 if(wp.flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) 5600 { 5601 //wstyle = GetWindowLongA(hwnd, GWL_STYLE); 5602 cbits |= CBits.VISIBLE; 5603 wstyle |= WS_VISIBLE; 5604 if(wp.flags & SWP_HIDEWINDOW) // Hiding. 5605 { 5606 cbits &= ~CBits.VISIBLE; 5607 wstyle &= ~WS_VISIBLE; 5608 } 5609 //break; // Showing min/max includes other flags. 5610 } 5611 } 5612 5613 //if(!(wp.flags & SWP_NOMOVE)) 5614 // wrect.location = Point(wp.x, wp.y); 5615 if(!(wp.flags & SWP_NOSIZE) || !(wp.flags & SWP_NOMOVE) || (wp.flags & SWP_FRAMECHANGED)) 5616 { 5617 //wrect = _fetchBounds(); 5618 wrect = Rect(wp.x, wp.y, wp.cx, wp.cy); 5619 wclientsz = _fetchClientSize(); 5620 } 5621 5622 if((wp.flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW)) || !(wp.flags & SWP_NOSIZE)) 5623 { 5624 DWORD rstyle; 5625 rstyle = GetWindowLongA(msg.hWnd, GWL_STYLE); 5626 rstyle &= WS_MAXIMIZE | WS_MINIMIZE; 5627 wstyle &= ~(WS_MAXIMIZE | WS_MINIMIZE); 5628 wstyle |= rstyle; 5629 } 5630 } 5631 break; 5632 5633 /+ 5634 case WM_WINDOWPOSCHANGING: 5635 //oldwrect = wrect; 5636 break; 5637 +/ 5638 5639 /+ 5640 case WM_SETFONT: 5641 //wfont = _fetchFont(); 5642 break; 5643 +/ 5644 5645 case WM_STYLECHANGED: 5646 { 5647 STYLESTRUCT* ss = cast(STYLESTRUCT*)msg.lParam; 5648 5649 if(msg.wParam == GWL_STYLE) 5650 wstyle = ss.styleNew; 5651 else if(msg.wParam == GWL_EXSTYLE) 5652 wexstyle = ss.styleNew; 5653 5654 /+ 5655 wrect = _fetchBounds(); 5656 wclientsz = _fetchClientSize(); 5657 +/ 5658 } 5659 break; 5660 5661 /+ 5662 // NOTE: this is sent even if the parent is shown. 5663 case WM_SHOWWINDOW: 5664 if(!msg.lParam) 5665 { 5666 /+ 5667 { 5668 cbits &= ~(CBits.SW_SHOWN | CBits.SW_HIDDEN); 5669 DWORD rstyle; 5670 rstyle = GetWindowLongA(msg.hWnd, GWL_STYLE); 5671 if(cast(BOOL)msg.wParam) 5672 { 5673 //wstyle |= WS_VISIBLE; 5674 if(!(WS_VISIBLE & wstyle) && (WS_VISIBLE & rstyle)) 5675 { 5676 wstyle = rstyle; 5677 cbits |= CBits.SW_SHOWN; 5678 5679 try 5680 { 5681 createChildren(); // Might throw. 5682 } 5683 catch(DThrowable e) 5684 { 5685 Application.onThreadException(e); 5686 } 5687 } 5688 wstyle = rstyle; 5689 } 5690 else 5691 { 5692 //wstyle &= ~WS_VISIBLE; 5693 if((WS_VISIBLE & wstyle) && !(WS_VISIBLE & rstyle)) 5694 { 5695 wstyle = rstyle; 5696 cbits |= CBits.SW_HIDDEN; 5697 } 5698 wstyle = rstyle; 5699 } 5700 } 5701 +/ 5702 wstyle = GetWindowLongA(msg.hWnd, GWL_STYLE); 5703 //if(cbits & CBits.FVISIBLE) 5704 // wstyle |= WS_VISIBLE; 5705 } 5706 break; 5707 +/ 5708 5709 case WM_ENABLE: 5710 /+ 5711 //if(IsWindowEnabled(hwnd)) 5712 if(cast(BOOL)msg.wParam) 5713 wstyle &= ~WS_DISABLED; 5714 else 5715 wstyle |= WS_DISABLED; 5716 +/ 5717 wstyle = GetWindowLongA(hwnd, GWL_STYLE); 5718 break; 5719 5720 /+ 5721 case WM_PARENTNOTIFY: 5722 switch(LOWORD(msg.wParam)) 5723 { 5724 case WM_DESTROY: 5725 // ... 5726 break; 5727 5728 default: 5729 } 5730 break; 5731 +/ 5732 5733 case WM_NCCREATE: 5734 { 5735 //hwnd = msg.hWnd; 5736 5737 /+ 5738 // Not using CREATESTRUCT for window bounds because it can contain 5739 // CW_USEDEFAULT and other magic values. 5740 5741 CREATESTRUCTA* cs; 5742 cs = cast(CREATESTRUCTA*)msg.lParam; 5743 5744 //wrect = Rect(cs.x, cs.y, cs.cx, cs.cy); 5745 +/ 5746 5747 wrect = _fetchBounds(); 5748 //oldwrect = wrect; 5749 wclientsz = _fetchClientSize(); 5750 } 5751 break; 5752 5753 case WM_CREATE: 5754 try 5755 { 5756 cbits |= CBits.CREATED; 5757 5758 //hwnd = msg.hWnd; 5759 5760 CREATESTRUCTA* cs; 5761 cs = cast(CREATESTRUCTA*)msg.lParam; 5762 /+ 5763 // Done in WM_NCCREATE now. 5764 //wrect = _fetchBounds(); 5765 wrect = Rect(cs.x, cs.y, cs.cx, cs.cy); 5766 wclientsz = _fetchClientSize(); 5767 +/ 5768 5769 // If class style was changed, update. 5770 if(_fetchClassLong() != wclassStyle) 5771 SetClassLongA(hwnd, GCL_STYLE, wclassStyle); 5772 5773 // Need to update clientSize in case of styles in createParams(). 5774 wclientsz = _fetchClientSize(); 5775 5776 //finishCreating(msg.hWnd); 5777 5778 if(!(ctrlStyle & ControlStyles.CACHE_TEXT)) 5779 wtext = null; 5780 5781 /+ 5782 // Gets created on demand instead. 5783 if(Color.empty != backc) 5784 { 5785 hbrBg = backc.createBrush(); 5786 } 5787 +/ 5788 5789 /+ 5790 // ? 5791 wstyle = cs.style; 5792 wexstyle = cs.dwExStyle; 5793 +/ 5794 5795 createChildren(); // Might throw. Used to be commented-out. 5796 5797 if(recreatingHandle) 5798 { 5799 // After existing messages and functions are done. 5800 delayInvoke(function(Control cthis, size_t[] params){ cthis.cbits &= ~CBits.RECREATING; }); 5801 } 5802 } 5803 catch(DThrowable e) 5804 { 5805 Application.onThreadException(e); 5806 } 5807 break; 5808 5809 case WM_DESTROY: 5810 cbits &= ~CBits.CREATED; 5811 if(!recreatingHandle) 5812 cbits &= ~CBits.FORMLOADED; 5813 _destroying(); 5814 //if(!killing) 5815 if(recreatingHandle) 5816 fillRecreationData(); 5817 break; 5818 5819 case WM_NCDESTROY: 5820 Application.removeHwnd(hwnd); 5821 hwnd = HWND.init; 5822 break; 5823 5824 default: 5825 /+ 5826 if(msg.msg == wmDfl) 5827 { 5828 switch(msg.wParam) 5829 { 5830 case WPARAM_DFL_: 5831 5832 default: 5833 } 5834 } 5835 +/ 5836 } 5837 } 5838 5839 5840 package final void _wndProc(ref Message msg) 5841 { 5842 //mustWndProc(msg); // Done in dflWndProc() now. 5843 wndProc(msg); 5844 } 5845 5846 5847 package final void _defWndProc(ref Message msg) 5848 { 5849 defWndProc(msg); 5850 } 5851 5852 5853 package final void doShow() 5854 { 5855 if(wparent) // Exclude owner. 5856 { 5857 SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER); 5858 } 5859 else 5860 { 5861 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); 5862 } 5863 } 5864 5865 5866 package final void doHide() 5867 { 5868 SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOZORDER); 5869 } 5870 5871 5872 //EventHandler backColorChanged; 5873 Event!(Control, EventArgs) backColorChanged; /// 5874 // EventHandler backgroundImageChanged; 5875 /+ 5876 deprecated EventHandler causesValidationChanged; 5877 deprecated InvalidateEventHandler invalidated; 5878 deprecated EventHandler validated; 5879 deprecated CancelEventHandler validating; // Once cancel is true, remaining events are suppressed (including validated). 5880 deprecated EventHandler enter; // Cascades up. TODO: fix implementation. 5881 deprecated EventHandler leave; // Cascades down. TODO: fix implementation. 5882 deprecated UICuesEventHandler changeUICues; // TODO: properly fire. 5883 +/ 5884 //EventHandler click; 5885 Event!(Control, EventArgs) click; /// 5886 version(DFL_NO_MENUS) 5887 { 5888 } 5889 else 5890 { 5891 //EventHandler contextMenuChanged; 5892 Event!(Control, EventArgs) contextMenuChanged; /// 5893 } 5894 //ControlEventHandler controlAdded; 5895 Event!(Control, ControlEventArgs) controlAdded; /// 5896 //ControlEventHandler controlRemoved; 5897 Event!(Control, ControlEventArgs) controlRemoved; /// 5898 //EventHandler cursorChanged; 5899 Event!(Control, EventArgs) cursorChanged; /// 5900 //EventHandler disposed; 5901 Event!(Control, EventArgs) disposed; /// 5902 //EventHandler dockChanged; 5903 //Event!(Control, EventArgs) dockChanged; /// 5904 Event!(Control, EventArgs) hasLayoutChanged; /// 5905 alias hasLayoutChanged dockChanged; 5906 //EventHandler doubleClick; 5907 Event!(Control, EventArgs) doubleClick; /// 5908 //EventHandler enabledChanged; 5909 Event!(Control, EventArgs) enabledChanged; /// 5910 //EventHandler fontChanged; 5911 Event!(Control, EventArgs) fontChanged; /// 5912 //EventHandler foreColorChanged; 5913 Event!(Control, EventArgs) foreColorChanged; /// 5914 //EventHandler gotFocus; // After enter. 5915 Event!(Control, EventArgs) gotFocus; /// 5916 //EventHandler handleCreated; 5917 Event!(Control, EventArgs) handleCreated; /// 5918 //EventHandler handleDestroyed; 5919 Event!(Control, EventArgs) handleDestroyed; /// 5920 //HelpEventHandler helpRequested; 5921 Event!(Control, HelpEventArgs) helpRequested; /// 5922 //KeyEventHandler keyDown; 5923 Event!(Control, KeyEventArgs) keyDown; /// 5924 //KeyEventHandler keyPress; 5925 Event!(Control, KeyPressEventArgs) keyPress; /// 5926 //KeyEventHandler keyUp; 5927 Event!(Control, KeyEventArgs) keyUp; /// 5928 //LayoutEventHandler layout; 5929 Event!(Control, LayoutEventArgs) layout; /// 5930 //EventHandler lostFocus; 5931 Event!(Control, EventArgs) lostFocus; /// 5932 //MouseEventHandler mouseDown; 5933 Event!(Control, MouseEventArgs) mouseDown; /// 5934 //MouseEventHandler mouseEnter; 5935 Event!(Control, MouseEventArgs) mouseEnter; /// 5936 //MouseEventHandler mouseHover; 5937 Event!(Control, MouseEventArgs) mouseHover; /// 5938 //MouseEventHandler mouseLeave; 5939 Event!(Control, MouseEventArgs) mouseLeave; /// 5940 //MouseEventHandler mouseMove; 5941 Event!(Control, MouseEventArgs) mouseMove; /// 5942 //MouseEventHandler mouseUp; 5943 Event!(Control, MouseEventArgs) mouseUp; /// 5944 //MouseEventHandler mouseWheel; 5945 Event!(Control, MouseEventArgs) mouseWheel; /// 5946 //EventHandler move; 5947 Event!(Control, EventArgs) move; /// 5948 //EventHandler locationChanged; 5949 alias move locationChanged; 5950 //PaintEventHandler paint; 5951 Event!(Control, PaintEventArgs) paint; /// 5952 //EventHandler parentChanged; 5953 Event!(Control, EventArgs) parentChanged; /// 5954 //EventHandler resize; 5955 Event!(Control, EventArgs) resize; /// 5956 //EventHandler sizeChanged; 5957 alias resize sizeChanged; 5958 //EventHandler rightToLeftChanged; 5959 Event!(Control, EventArgs) rightToLeftChanged; /// 5960 // EventHandler styleChanged; 5961 //EventHandler systemColorsChanged; 5962 Event!(Control, EventArgs) systemColorsChanged; /// 5963 // EventHandler tabIndexChanged; 5964 // EventHandler tabStopChanged; 5965 //EventHandler textChanged; 5966 Event!(Control, EventArgs) textChanged; /// 5967 //EventHandler visibleChanged; 5968 Event!(Control, EventArgs) visibleChanged; /// 5969 5970 version(DFL_NO_DRAG_DROP) {} else 5971 { 5972 //DragEventHandler dragDrop; 5973 Event!(Control, DragEventArgs) dragDrop; /// 5974 //DragEventHandler dragEnter; 5975 Event!(Control, DragEventArgs) dragEnter; /// 5976 //EventHandler dragLeave; 5977 Event!(Control, EventArgs) dragLeave; /// 5978 //DragEventHandler dragOver; 5979 Event!(Control, DragEventArgs) dragOver; /// 5980 //GiveFeedbackEventHandler giveFeedback; 5981 Event!(Control, GiveFeedbackEventArgs) giveFeedback; /// 5982 //QueryContinueDragEventHandler queryContinueDrag; 5983 Event!(Control, QueryContinueDragEventArgs) queryContinueDrag; /// 5984 } 5985 5986 5987 /// Construct a new Control instance. 5988 this() 5989 { 5990 //name = DObject.toString(); // ? 5991 5992 wrect.size = defaultSize; 5993 //oldwrect = wrect; 5994 5995 /+ 5996 backc = defaultBackColor; 5997 forec = defaultForeColor; 5998 wfont = defaultFont; 5999 wcurs = new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false); 6000 +/ 6001 backc = Color.empty; 6002 forec = Color.empty; 6003 wfont = null; 6004 wcurs = null; 6005 6006 ccollection = createControlsInstance(); 6007 } 6008 6009 /// ditto 6010 this(Dstring text) 6011 { 6012 this(); 6013 wtext = text; 6014 6015 ccollection = createControlsInstance(); 6016 } 6017 6018 /// ditto 6019 this(Control cparent, Dstring text) 6020 { 6021 this(); 6022 wtext = text; 6023 parent = cparent; 6024 6025 ccollection = createControlsInstance(); 6026 } 6027 6028 /// ditto 6029 this(Dstring text, int left, int top, int width, int height) 6030 { 6031 this(); 6032 wtext = text; 6033 wrect = Rect(left, top, width, height); 6034 6035 ccollection = createControlsInstance(); 6036 } 6037 6038 /// ditto 6039 this(Control cparent, Dstring text, int left, int top, int width, int height) 6040 { 6041 this(); 6042 wtext = text; 6043 wrect = Rect(left, top, width, height); 6044 parent = cparent; 6045 6046 ccollection = createControlsInstance(); 6047 } 6048 6049 6050 /+ 6051 // Used internally. 6052 this(HWND hwnd) 6053 in 6054 { 6055 assert(hwnd); 6056 } 6057 body 6058 { 6059 this.hwnd = hwnd; 6060 owned = false; 6061 6062 ccollection = new ControlCollection(this); 6063 } 6064 +/ 6065 6066 6067 ~this() 6068 { 6069 debug(APP_PRINT) 6070 cprintf("~Control %p\n", cast(void*)this); 6071 6072 version(DFL_NO_ZOMBIE_FORM) 6073 { 6074 } 6075 else 6076 { 6077 Application.zombieKill(this); // Does nothing if not zombie. 6078 } 6079 6080 //dispose(false); 6081 destroyHandle(); 6082 deleteThisBackgroundBrush(); 6083 } 6084 6085 6086 /+ package +/ /+ protected +/ int _rtype() // package 6087 { 6088 return 0; 6089 } 6090 6091 6092 /// 6093 void dispose() 6094 { 6095 dispose(true); 6096 } 6097 6098 /// ditto 6099 protected void dispose(bool disposing) 6100 { 6101 if(disposing) 6102 { 6103 killing = true; 6104 6105 version(DFL_NO_MENUS) 6106 { 6107 } 6108 else 6109 { 6110 cmenu = cmenu.init; 6111 } 6112 _ctrlname = _ctrlname.init; 6113 otag = otag.init; 6114 wcurs = wcurs.init; 6115 wfont = wfont.init; 6116 wparent = wparent.init; 6117 wregion = wregion.init; 6118 wtext = wtext.init; 6119 deleteThisBackgroundBrush(); 6120 //ccollection.children = null; // Not GC-safe in dtor. 6121 //ccollection = null; // ? Causes bad things. Leaving it will do just fine. 6122 } 6123 6124 if(!isHandleCreated) 6125 return; 6126 6127 destroyHandle(); 6128 /+ 6129 //assert(hwnd == HWND.init); // Zombie trips this. (Not anymore with the hwnd-prop) 6130 if(hwnd) 6131 { 6132 assert(!IsWindow(hwnd)); 6133 hwnd = HWND.init; 6134 } 6135 +/ 6136 assert(hwnd == HWND.init); 6137 6138 onDisposed(EventArgs.empty); 6139 } 6140 6141 6142 protected: 6143 6144 /// 6145 @property Size defaultSize() // getter 6146 { 6147 return Size(0, 0); 6148 } 6149 6150 6151 /+ 6152 // TODO: implement. 6153 @property EventHandlerList events() // getter 6154 { 6155 } 6156 +/ 6157 6158 6159 /+ 6160 // TODO: implement. Is this worth implementing? 6161 6162 // Set to -1 to reset cache. 6163 final @property void fontHeight(int fh) // setter 6164 { 6165 6166 } 6167 6168 6169 final @property int fontHeight() // getter 6170 { 6171 return fonth; 6172 } 6173 +/ 6174 6175 6176 /// 6177 //final void resizeRedraw(bool byes) // setter 6178 public final @property void resizeRedraw(bool byes) // setter 6179 { 6180 /+ 6181 // These class styles get lost sometimes so don't rely on them. 6182 LONG cl = _classStyle(); 6183 if(byes) 6184 cl |= CS_HREDRAW | CS_VREDRAW; 6185 else 6186 cl &= ~(CS_HREDRAW | CS_VREDRAW); 6187 6188 _classStyle(cl); 6189 +/ 6190 szdraw = byes; 6191 } 6192 6193 /// ditto 6194 final @property bool resizeRedraw() // getter 6195 { 6196 //return (_classStyle() & (CS_HREDRAW | CS_VREDRAW)) != 0; 6197 return szdraw; 6198 } 6199 6200 6201 /+ 6202 // /// 6203 // I don't think this is reliable. 6204 final bool hasVisualStyle() // getter 6205 { 6206 bool result = false; 6207 HWND hw = handle; // Always reference handle. 6208 HMODULE huxtheme = GetModuleHandleA("uxtheme.dll"); 6209 //HMODULE huxtheme = LoadLibraryA("uxtheme.dll"); 6210 if(huxtheme) 6211 { 6212 auto getwintheme = cast(typeof(&GetWindowTheme))GetProcAddress(huxtheme, "GetWindowTheme"); 6213 if(getwintheme) 6214 { 6215 result = getwintheme(hw) != null; 6216 } 6217 //FreeLibrary(huxtheme); 6218 } 6219 return result; 6220 } 6221 +/ 6222 6223 6224 package final void _disableVisualStyle() 6225 { 6226 assert(isHandleCreated); 6227 6228 HMODULE hmuxt; 6229 hmuxt = GetModuleHandleA("uxtheme.dll"); 6230 if(hmuxt) 6231 { 6232 auto setWinTheme = cast(typeof(&SetWindowTheme))GetProcAddress(hmuxt, "SetWindowTheme"); 6233 if(setWinTheme) 6234 { 6235 setWinTheme(hwnd, " "w.ptr, " "w.ptr); // Clear the theme. 6236 } 6237 } 6238 } 6239 6240 6241 /// 6242 public final void disableVisualStyle(bool byes = true) 6243 { 6244 if(!byes) 6245 { 6246 if(cbits & CBits.VSTYLE) 6247 return; 6248 cbits |= CBits.VSTYLE; 6249 6250 if(isHandleCreated) 6251 { 6252 _crecreate(); 6253 } 6254 } 6255 else 6256 { 6257 if(!(cbits & CBits.VSTYLE)) 6258 return; 6259 cbits &= ~CBits.VSTYLE; 6260 6261 if(isHandleCreated) 6262 _disableVisualStyle(); 6263 } 6264 } 6265 6266 deprecated public final void enableVisualStyle(bool byes = true) 6267 { 6268 return disableVisualStyle(!byes); 6269 } 6270 6271 6272 /// 6273 ControlCollection createControlsInstance() 6274 { 6275 return new ControlCollection(this); 6276 } 6277 6278 6279 deprecated package final void createClassHandle(Dstring className) 6280 { 6281 if(!wparent || !wparent.handle || killing) 6282 { 6283 create_err: 6284 throw new DflException("Control creation failure"); 6285 } 6286 6287 // This is here because referencing wparent.handle might create me. 6288 //if(created) 6289 if(isHandleCreated) 6290 return; 6291 6292 Application.creatingControl(this); 6293 hwnd = dfl.internal.utf.createWindowEx(wexstyle, className, wtext, wstyle, wrect.x, wrect.y, 6294 wrect.width, wrect.height, wparent.handle, HMENU.init, Application.getInstance(), null); 6295 if(!hwnd) 6296 goto create_err; 6297 } 6298 6299 6300 /// 6301 // Override to change the creation parameters. 6302 // Be sure to call super.createParams() or all the create params will need to be filled. 6303 protected void createParams(ref CreateParams cp) 6304 { 6305 with(cp) 6306 { 6307 className = CONTROL_CLASSNAME; 6308 caption = wtext; 6309 param = null; 6310 //parent = wparent.handle; 6311 parent = wparent ? wparent.handle : HWND.init; 6312 menu = HMENU.init; 6313 inst = Application.getInstance(); 6314 x = wrect.x; 6315 y = wrect.y; 6316 width = wrect.width; 6317 height = wrect.height; 6318 classStyle = wclassStyle; 6319 exStyle = wexstyle; 6320 wstyle |= WS_VISIBLE; 6321 if(!(cbits & CBits.VISIBLE)) 6322 wstyle &= ~WS_VISIBLE; 6323 style = wstyle; 6324 } 6325 } 6326 6327 6328 /// 6329 protected void createHandle() 6330 { 6331 // Note: if modified, Form.createHandle() should be modified as well. 6332 6333 if(isHandleCreated) 6334 return; 6335 6336 //createClassHandle(CONTROL_CLASSNAME); 6337 6338 /+ 6339 if(!wparent || !wparent.handle || killing) 6340 { 6341 create_err: 6342 //throw new DflException("Control creation failure"); 6343 throw new DflException(Object.toString() ~ " creation failure"); // ? 6344 } 6345 +/ 6346 6347 debug 6348 { 6349 Dstring er; 6350 } 6351 if(killing) 6352 { 6353 debug 6354 { 6355 er = "the control is being disposed"; 6356 } 6357 6358 debug(APP_PRINT) 6359 { 6360 cprintf("Creating Control handle while disposing.\n"); 6361 } 6362 6363 create_err: 6364 Dstring kmsg = "Control creation failure"; 6365 if(name.length) 6366 kmsg ~= " (" ~ name ~ ")"; 6367 debug 6368 { 6369 if(er.length) 6370 kmsg ~= " - " ~ er; 6371 } 6372 throw new DflException(kmsg); 6373 //throw new DflException(Object.toString() ~ " creation failure"); // ? 6374 } 6375 6376 // Need the parent's handle to exist. 6377 if(wparent) 6378 wparent.createHandle(); 6379 6380 // This is here because wparent.createHandle() might create me. 6381 //if(created) 6382 if(isHandleCreated) 6383 return; 6384 6385 CreateParams cp; 6386 /+ 6387 DWORD prevClassStyle; 6388 prevClassStyle = wclassStyle; 6389 +/ 6390 6391 createParams(cp); 6392 assert(!isHandleCreated); // Make sure the handle wasn't created in createParams(). 6393 6394 with(cp) 6395 { 6396 wtext = caption; 6397 //wrect = Rect(x, y, width, height); // This gets updated in WM_CREATE. 6398 wclassStyle = classStyle; 6399 wexstyle = exStyle; 6400 wstyle = style; 6401 6402 //if(style & WS_CHILD) // Breaks context-help. 6403 if((ctrlStyle & ControlStyles.CONTAINER_CONTROL) && (style & WS_CHILD)) 6404 { 6405 exStyle |= WS_EX_CONTROLPARENT; 6406 } 6407 6408 bool vis = (style & WS_VISIBLE) != 0; 6409 6410 Application.creatingControl(this); 6411 hwnd = dfl.internal.utf.createWindowEx(exStyle, className, caption, (style & ~WS_VISIBLE), x, y, 6412 width, height, parent, menu, inst, param); 6413 if(!hwnd) 6414 { 6415 debug(APP_PRINT) 6416 { 6417 cprintf("CreateWindowEx failed." 6418 " (exStyle=0x%X, className=`%.*s`, caption=`%.*s`, style=0x%X, x=%d, y=%d, width=%d, height=%d," 6419 " parent=0x%X, menu=0x%X, inst=0x%X, param=0x%X)\n", 6420 exStyle, className, caption, style, x, y, width, height, 6421 parent, menu, inst, param); 6422 } 6423 6424 debug 6425 { 6426 er = std..string.format("CreateWindowEx failed {className=%s;exStyle=0x%X;style=0x%X;parent=0x%X;menu=0x%X;inst=0x%X;}", 6427 className, exStyle, style, cast(void*)parent, cast(void*)menu, cast(void*)inst); 6428 } 6429 6430 goto create_err; 6431 } 6432 6433 if(vis) 6434 doShow(); // Properly fires onVisibleChanged. 6435 } 6436 6437 //onHandleCreated(EventArgs.empty); // Called in WM_CREATE now. 6438 } 6439 6440 6441 package final void _createHandle() 6442 { 6443 createHandle(); 6444 } 6445 6446 6447 /// 6448 public final @property bool recreatingHandle() // getter 6449 { 6450 if(cbits & CBits.RECREATING) 6451 return true; 6452 return false; 6453 } 6454 6455 6456 private void _setAllRecreating() 6457 { 6458 cbits |= CBits.RECREATING; 6459 foreach(Control cc; controls) 6460 { 6461 cc._setAllRecreating(); 6462 } 6463 } 6464 6465 6466 /// 6467 protected void recreateHandle() 6468 in 6469 { 6470 assert(!recreatingHandle); 6471 } 6472 body 6473 { 6474 if(!isHandleCreated) 6475 return; 6476 6477 if(recreatingHandle) 6478 return; 6479 6480 bool hfocus = focused; 6481 HWND prevHwnd = GetWindow(hwnd, GW_HWNDPREV); 6482 6483 _setAllRecreating(); 6484 //scope(exit) 6485 // cbits &= ~CBits.RECREATING; // Now done from WM_CREATE. 6486 6487 destroyHandle(); 6488 createHandle(); 6489 6490 if(prevHwnd) 6491 SetWindowPos(hwnd, prevHwnd, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); 6492 else 6493 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); 6494 if(hfocus) 6495 select(); 6496 } 6497 6498 6499 /// 6500 void destroyHandle() 6501 { 6502 if(!isHandleCreated) 6503 return; 6504 6505 DestroyWindow(hwnd); 6506 6507 // This stuff is done in WM_DESTROY because DestroyWindow() could be called elsewhere.. 6508 //hwnd = HWND.init; // Done in WM_DESTROY. 6509 //onHandleDestroyed(EventArgs.empty); // Done in WM_DESTROY. 6510 } 6511 6512 6513 private final void fillRecreationData() 6514 { 6515 //cprintf(" { fillRecreationData %.*s }\n", name); 6516 6517 if(!(ctrlStyle & ControlStyles.CACHE_TEXT)) 6518 wtext = _fetchText(); 6519 6520 //wclassStyle = _fetchClassLong(); // ? 6521 6522 // Fetch children. 6523 Control[] ccs; 6524 foreach(Control cc; controls) 6525 { 6526 ccs ~= cc; 6527 } 6528 ccollection.children = ccs; 6529 } 6530 6531 6532 /// 6533 protected void onDisposed(EventArgs ea) 6534 { 6535 disposed(this, ea); 6536 } 6537 6538 6539 /// 6540 protected final bool getStyle(ControlStyles flag) 6541 { 6542 return (ctrlStyle & flag) != 0; 6543 } 6544 6545 /// ditto 6546 protected final void setStyle(ControlStyles flag, bool value) 6547 { 6548 if(flag & ControlStyles.CACHE_TEXT) 6549 { 6550 if(value) 6551 wtext = _fetchText(); 6552 else 6553 wtext = null; 6554 } 6555 6556 if(value) 6557 ctrlStyle |= flag; 6558 else 6559 ctrlStyle &= ~flag; 6560 } 6561 6562 6563 /// 6564 // Only for setStyle() styles that are part of hwnd and wndclass styles. 6565 protected final void updateStyles() 6566 { 6567 LONG newClassStyles = _classStyle(); 6568 LONG newWndStyles = _style(); 6569 6570 if(ctrlStyle & ControlStyles.STANDARD_DOUBLE_CLICK) 6571 newClassStyles |= CS_DBLCLKS; 6572 else 6573 newClassStyles &= ~CS_DBLCLKS; 6574 6575 /+ 6576 if(ctrlStyle & ControlStyles.RESIZE_REDRAW) 6577 newClassStyles |= CS_HREDRAW | CS_VREDRAW; 6578 else 6579 newClassStyles &= ~(CS_HREDRAW | CS_VREDRAW); 6580 +/ 6581 6582 /+ 6583 if(ctrlStyle & ControlStyles.SELECTABLE) 6584 newWndStyles |= WS_TABSTOP; 6585 else 6586 newWndStyles &= ~WS_TABSTOP; 6587 +/ 6588 6589 _classStyle(newClassStyles); 6590 _style(newWndStyles); 6591 } 6592 6593 6594 /// 6595 final bool getTopLevel() 6596 { 6597 // return GetParent(hwnd) == HWND.init; 6598 return wparent is null; 6599 } 6600 6601 6602 package final void alayout(Control ctrl, bool vcheck = true) 6603 { 6604 if(vcheck && !visible) 6605 return; 6606 6607 if(cbits & CBits.IN_LAYOUT) 6608 return; 6609 6610 //if(_allowLayout) 6611 if(!_disallowLayout) 6612 { 6613 //cprintf("alayout\n"); 6614 scope LayoutEventArgs lea = new LayoutEventArgs(ctrl); 6615 onLayout(lea); 6616 } 6617 } 6618 6619 6620 // Z-order of controls has changed. 6621 package final void vchanged() 6622 { 6623 // Z-order can't change if it's not created or invisible. 6624 //if(!isHandleCreated || !visible) 6625 // return; 6626 6627 version(RADIO_GROUP_LAYOUT) 6628 { 6629 //cprintf("vchanged\n"); 6630 6631 bool foundRadio = false; 6632 6633 foreach(Control ctrl; ccollection) 6634 { 6635 if(!ctrl.visible) 6636 continue; 6637 6638 if(ctrl._rtype() & 1) // Radio type. 6639 { 6640 LONG wlg; 6641 wlg = ctrl._style(); 6642 if(foundRadio) 6643 { 6644 if(wlg & WS_GROUP) 6645 //ctrl._style(wlg & ~WS_GROUP); 6646 ctrl._style(wlg & ~(WS_GROUP | WS_TABSTOP)); 6647 } 6648 else 6649 { 6650 foundRadio = true; 6651 6652 if(!(wlg & WS_GROUP)) 6653 //ctrl._style(wlg | WS_GROUP); 6654 ctrl._style(wlg | WS_GROUP | WS_TABSTOP); 6655 } 6656 } 6657 else 6658 { 6659 // Found non-radio so reset group. 6660 // Update: only reset group if found ctrl with WS_EX_CONTROLPARENT. 6661 // TODO: check if correct implementation. 6662 if(ctrl._exStyle() & WS_EX_CONTROLPARENT) 6663 foundRadio = false; 6664 } 6665 } 6666 } 6667 } 6668 6669 6670 /// 6671 // Called after adding the control to a container. 6672 protected void initLayout() 6673 { 6674 assert(wparent !is null); 6675 if(visible && created) // ? 6676 { 6677 wparent.vchanged(); 6678 wparent.alayout(this); 6679 } 6680 } 6681 6682 6683 /// 6684 protected void onLayout(LayoutEventArgs lea) 6685 { 6686 // Note: exception could cause failure to restore. 6687 //suspendLayout(); 6688 cbits |= CBits.IN_LAYOUT; 6689 6690 debug(EVENT_PRINT) 6691 { 6692 cprintf("{ Event: onLayout - Control %.*s }\n", name); 6693 } 6694 6695 Rect area; 6696 area = displayRectangle; 6697 6698 foreach(Control ctrl; ccollection) 6699 { 6700 if(!ctrl.visible || !ctrl.created) 6701 continue; 6702 if(ctrl._rtype() & (2 | 4)) // Mdichild | Tabpage 6703 continue; 6704 6705 //Rect prevctrlbounds; 6706 //prevctrlbounds = ctrl.bounds; 6707 //ctrl.suspendLayout(); // Note: exception could cause failure to restore. 6708 switch(ctrl.sdock) 6709 { 6710 case DockStyle.NONE: 6711 /+ 6712 if(ctrl.anch & (AnchorStyles.RIGHT | AnchorStyles.BOTTOM)) // If none of these are set, no point in doing any anchor code. 6713 { 6714 Rect newb; 6715 newb = ctrl.bounds; 6716 if(ctrl.anch & AnchorStyles.RIGHT) 6717 { 6718 if(ctrl.anch & AnchorStyles.LEFT) 6719 newb.width += bounds.width - originalBounds.width; 6720 else 6721 newb.x += bounds.width - originalBounds.width; 6722 } 6723 if(ctrl.anch & AnchorStyles.BOTTOM) 6724 { 6725 if(ctrl.anch & AnchorStyles.LEFT) 6726 newb.height += bounds.height - originalBounds.height; 6727 else 6728 newb.y += bounds.height - originalBounds.height; 6729 } 6730 if(newb != ctrl.bounds) 6731 ctrl.bounds = newb; 6732 } 6733 +/ 6734 break; 6735 6736 case DockStyle.LEFT: 6737 ctrl.setBoundsCore(area.x, area.y, 0, area.height, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT)); 6738 area.x = area.x + ctrl.width; 6739 area.width = area.width - ctrl.width; 6740 break; 6741 6742 case DockStyle.TOP: 6743 ctrl.setBoundsCore(area.x, area.y, area.width, 0, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH)); 6744 area.y = area.y + ctrl.height; 6745 area.height = area.height - ctrl.height; 6746 break; 6747 6748 case DockStyle.FILL: 6749 //ctrl.bounds(Rect(area.x, area.y, area.width, area.height)); 6750 ctrl.bounds = area; 6751 // area = ? 6752 break; 6753 6754 case DockStyle.BOTTOM: 6755 ctrl.setBoundsCore(area.x, area.bottom - ctrl.height, area.width, 0, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH)); 6756 area.height = area.height - ctrl.height; 6757 break; 6758 6759 case DockStyle.RIGHT: 6760 ctrl.setBoundsCore(area.right - ctrl.width, area.y, 0, area.height, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT)); 6761 area.width = area.width - ctrl.width; 6762 break; 6763 6764 default: 6765 assert(0); 6766 } 6767 //ctrl.resumeLayout(true); 6768 //ctrl.resumeLayout(prevctrlbounds != ctrl.bounds); 6769 } 6770 6771 layout(this, lea); 6772 6773 //resumeLayout(false); 6774 cbits &= ~CBits.IN_LAYOUT; 6775 } 6776 6777 6778 /+ 6779 // Not sure what to do here. 6780 deprecated bool isInputChar(char charCode) 6781 { 6782 return false; 6783 } 6784 +/ 6785 6786 6787 /// 6788 void setVisibleCore(bool byes) 6789 { 6790 if(isHandleCreated) 6791 { 6792 //wstyle = GetWindowLongA(hwnd, GWL_STYLE); 6793 if(visible == byes) 6794 return; 6795 6796 //ShowWindow(hwnd, byes ? SW_SHOW : SW_HIDE); 6797 if(byes) 6798 doShow(); 6799 else 6800 doHide(); 6801 } 6802 else 6803 { 6804 if(byes) 6805 { 6806 cbits |= CBits.VISIBLE; 6807 wstyle |= WS_VISIBLE; 6808 createControl(); 6809 } 6810 else 6811 { 6812 cbits &= ~CBits.VISIBLE; 6813 wstyle &= ~WS_VISIBLE; 6814 return; // Not created and being hidden.. 6815 } 6816 } 6817 } 6818 6819 6820 package final bool _wantTabKey() 6821 { 6822 if(ctrlStyle & ControlStyles.WANT_TAB_KEY) 6823 return true; 6824 return false; 6825 } 6826 6827 6828 /// 6829 // Return true if processed. 6830 protected bool processKeyEventArgs(ref Message msg) 6831 { 6832 switch(msg.msg) 6833 { 6834 case WM_KEYDOWN: 6835 { 6836 scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys)); 6837 6838 ushort repeat = msg.lParam & 0xFFFF; // First 16 bits. 6839 for(; repeat; repeat--) 6840 { 6841 //kea.handled = false; 6842 onKeyDown(kea); 6843 } 6844 6845 if(kea.handled) 6846 return true; 6847 } 6848 break; 6849 6850 case WM_KEYUP: 6851 { 6852 // Repeat count is always 1 for key up. 6853 scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys)); 6854 onKeyUp(kea); 6855 if(kea.handled) 6856 return true; 6857 } 6858 break; 6859 6860 case WM_CHAR: 6861 { 6862 scope KeyPressEventArgs kpea = new KeyPressEventArgs(cast(dchar)msg.wParam, modifierKeys); 6863 onKeyPress(kpea); 6864 if(kpea.handled) 6865 return true; 6866 } 6867 break; 6868 6869 default: 6870 } 6871 6872 defWndProc(msg); 6873 return !msg.result; 6874 } 6875 6876 6877 package final bool _processKeyEventArgs(ref Message msg) 6878 { 6879 return processKeyEventArgs(msg); 6880 } 6881 6882 6883 /+ 6884 bool processKeyPreview(ref Message m) 6885 { 6886 if(wparent) 6887 return wparent.processKeyPreview(m); 6888 return false; 6889 } 6890 6891 6892 protected bool processDialogChar(dchar charCode) 6893 { 6894 if(wparent) 6895 return wparent.processDialogChar(charCode); 6896 return false; 6897 } 6898 +/ 6899 6900 6901 /// 6902 protected bool processMnemonic(dchar charCode) 6903 { 6904 return false; 6905 } 6906 6907 6908 package bool _processMnemonic(dchar charCode) 6909 { 6910 return processMnemonic(charCode); 6911 } 6912 6913 6914 // Retain DFL 0.9.5 compatibility. 6915 public deprecated void setDFL095() 6916 { 6917 version(SET_DFL_095) 6918 { 6919 pragma(msg, "DFL: DFL 0.9.5 compatibility set at compile time"); 6920 } 6921 else 6922 { 6923 //_compat = CCompat.DFL095; 6924 Application.setCompat(DflCompat.CONTROL_RECREATE_095); 6925 } 6926 } 6927 6928 private enum CCompat: ubyte 6929 { 6930 NONE = 0, 6931 DFL095 = 1, 6932 } 6933 6934 version(SET_DFL_095) 6935 package enum _compat = CCompat.DFL095; 6936 else version(DFL_NO_COMPAT) 6937 package enum _compat = CCompat.NONE; 6938 else 6939 package @property CCompat _compat() // getter 6940 { if(Application._compat & DflCompat.CONTROL_RECREATE_095) return CCompat.DFL095; return CCompat.NONE; } 6941 6942 6943 package final void _crecreate() 6944 { 6945 if(CCompat.DFL095 != _compat) 6946 { 6947 if(!recreatingHandle) 6948 recreateHandle(); 6949 } 6950 } 6951 6952 6953 package: 6954 HWND hwnd; 6955 //AnchorStyles anch = cast(AnchorStyles)(AnchorStyles.TOP | AnchorStyles.LEFT); 6956 //bool cvalidation = true; 6957 version(DFL_NO_MENUS) 6958 { 6959 } 6960 else 6961 { 6962 ContextMenu cmenu; 6963 } 6964 DockStyle sdock = DockStyle.NONE; 6965 Dstring _ctrlname; 6966 Object otag; 6967 Color backc, forec; 6968 Rect wrect; 6969 //Rect oldwrect; 6970 Size wclientsz; 6971 Cursor wcurs; 6972 Font wfont; 6973 Control wparent; 6974 Region wregion; 6975 ControlCollection ccollection; 6976 Dstring wtext; // After creation, this isn't used unless ControlStyles.CACHE_TEXT. 6977 ControlStyles ctrlStyle = ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK /+ | ControlStyles.RESIZE_REDRAW +/ ; 6978 HBRUSH _hbrBg; 6979 RightToLeft rtol = RightToLeft.INHERIT; 6980 uint _disallowLayout = 0; 6981 6982 version(DFL_NO_DRAG_DROP) {} else 6983 { 6984 DropTarget droptarget = null; 6985 } 6986 6987 // Note: WS_VISIBLE is not reliable. 6988 LONG wstyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; // Child, visible and enabled by default. 6989 LONG wexstyle; 6990 LONG wclassStyle = WNDCLASS_STYLE; 6991 6992 6993 enum CBits: uint 6994 { 6995 NONE = 0x0, 6996 MENTER = 0x1, // Is mouse entered? Only valid if -trackMouseEvent- is non-null. 6997 KILLING = 0x2, 6998 OWNED = 0x4, 6999 //ALLOW_LAYOUT = 0x8, 7000 CLICKING = 0x10, 7001 NEED_CALC_SIZE = 0x20, 7002 SZDRAW = 0x40, 7003 OWNEDBG = 0x80, 7004 HANDLE_CREATED = 0x100, // debug only 7005 SW_SHOWN = 0x200, 7006 SW_HIDDEN = 0x400, 7007 CREATED = 0x800, 7008 NEED_INIT_LAYOUT = 0x1000, 7009 IN_LAYOUT = 0x2000, 7010 FVISIBLE = 0x4000, 7011 VISIBLE = 0x8000, 7012 NOCLOSING = 0x10000, 7013 ASCROLL = 0x20000, 7014 ASCALE = 0x40000, 7015 FORM = 0x80000, 7016 RECREATING = 0x100000, 7017 HAS_LAYOUT = 0x200000, 7018 VSTYLE = 0x400000, // If not forced off. 7019 FORMLOADED = 0x800000, // If not forced off. 7020 ENABLED = 0x1000000, // Enabled state, not considering the parent. 7021 } 7022 7023 //CBits cbits = CBits.ALLOW_LAYOUT; 7024 //CBits cbits = CBits.NONE; 7025 CBits cbits = CBits.VISIBLE | CBits.VSTYLE | CBits.ENABLED; 7026 7027 7028 final: 7029 7030 @property void menter(bool byes) // setter 7031 { if(byes) cbits |= CBits.MENTER; else cbits &= ~CBits.MENTER; } 7032 @property bool menter() // getter 7033 { return (cbits & CBits.MENTER) != 0; } 7034 7035 @property void killing(bool byes) // setter 7036 //{ if(byes) cbits |= CBits.KILLING; else cbits &= ~CBits.KILLING; } 7037 { assert(byes); if(byes) cbits |= CBits.KILLING; } 7038 @property bool killing() // getter 7039 { return (cbits & CBits.KILLING) != 0; } 7040 7041 @property void owned(bool byes) // setter 7042 { if(byes) cbits |= CBits.OWNED; else cbits &= ~CBits.OWNED; } 7043 @property bool owned() // getter 7044 { return (cbits & CBits.OWNED) != 0; } 7045 7046 /+ 7047 void _allowLayout(bool byes) // setter 7048 { if(byes) cbits |= CBits.ALLOW_LAYOUT; else cbits &= ~CBits.ALLOW_LAYOUT; } 7049 bool _allowLayout() // getter 7050 { return (cbits & CBits.ALLOW_LAYOUT) != 0; } 7051 +/ 7052 7053 @property void _clicking(bool byes) // setter 7054 { if(byes) cbits |= CBits.CLICKING; else cbits &= ~CBits.CLICKING; } 7055 @property bool _clicking() // getter 7056 { return (cbits & CBits.CLICKING) != 0; } 7057 7058 @property void needCalcSize(bool byes) // setter 7059 { if(byes) cbits |= CBits.NEED_CALC_SIZE; else cbits &= ~CBits.NEED_CALC_SIZE; } 7060 @property bool needCalcSize() // getter 7061 { return (cbits & CBits.NEED_CALC_SIZE) != 0; } 7062 7063 @property void szdraw(bool byes) // setter 7064 { if(byes) cbits |= CBits.SZDRAW; else cbits &= ~CBits.SZDRAW; } 7065 @property bool szdraw() // getter 7066 { return (cbits & CBits.SZDRAW) != 0; } 7067 7068 @property void ownedbg(bool byes) // setter 7069 { if(byes) cbits |= CBits.OWNEDBG; else cbits &= ~CBits.OWNEDBG; } 7070 @property bool ownedbg() // getter 7071 { return (cbits & CBits.OWNEDBG) != 0; } 7072 7073 debug 7074 { 7075 @property void _handlecreated(bool byes) // setter 7076 { if(byes) cbits |= CBits.HANDLE_CREATED; else cbits &= ~CBits.HANDLE_CREATED; } 7077 @property bool _handlecreated() // getter 7078 { return (cbits & CBits.HANDLE_CREATED) != 0; } 7079 } 7080 7081 7082 @property LONG _exStyle() 7083 { 7084 // return GetWindowLongA(hwnd, GWL_EXSTYLE); 7085 return wexstyle; 7086 } 7087 7088 7089 @property void _exStyle(LONG wl) 7090 { 7091 if(isHandleCreated) 7092 { 7093 SetWindowLongA(hwnd, GWL_EXSTYLE, wl); 7094 } 7095 7096 wexstyle = wl; 7097 } 7098 7099 7100 @property LONG _style() 7101 { 7102 // return GetWindowLongA(hwnd, GWL_STYLE); 7103 return wstyle; 7104 } 7105 7106 7107 @property void _style(LONG wl) 7108 { 7109 if(isHandleCreated) 7110 { 7111 SetWindowLongA(hwnd, GWL_STYLE, wl); 7112 } 7113 7114 wstyle = wl; 7115 } 7116 7117 7118 @property HBRUSH hbrBg() // getter 7119 { 7120 if(_hbrBg) 7121 return _hbrBg; 7122 if(backc == Color.empty && parent && backColor == parent.backColor) 7123 { 7124 ownedbg = false; 7125 _hbrBg = parent.hbrBg; 7126 return _hbrBg; 7127 } 7128 hbrBg = backColor.createBrush(); // Call hbrBg's setter and set ownedbg. 7129 return _hbrBg; 7130 } 7131 7132 7133 @property void hbrBg(HBRUSH hbr) // setter 7134 in 7135 { 7136 if(hbr) 7137 { 7138 assert(!_hbrBg); 7139 } 7140 } 7141 body 7142 { 7143 _hbrBg = hbr; 7144 ownedbg = true; 7145 } 7146 7147 7148 void deleteThisBackgroundBrush() 7149 { 7150 if(_hbrBg) 7151 { 7152 if(ownedbg) 7153 DeleteObject(_hbrBg); 7154 _hbrBg = HBRUSH.init; 7155 } 7156 } 7157 7158 7159 LRESULT defwproc(UINT msg, WPARAM wparam, LPARAM lparam) 7160 { 7161 //return DefWindowProcA(hwnd, msg, wparam, lparam); 7162 return dfl.internal.utf.defWindowProc(hwnd, msg, wparam, lparam); 7163 } 7164 7165 7166 LONG _fetchClassLong() 7167 { 7168 return GetClassLongA(hwnd, GCL_STYLE); 7169 } 7170 7171 7172 LONG _classStyle() 7173 { 7174 // return GetClassLongA(hwnd, GCL_STYLE); 7175 // return wclassStyle; 7176 7177 if(isHandleCreated) 7178 { 7179 // Always fetch because it's not guaranteed to be accurate. 7180 wclassStyle = _fetchClassLong(); 7181 } 7182 7183 return wclassStyle; 7184 } 7185 7186 7187 package void _classStyle(LONG cl) 7188 { 7189 if(isHandleCreated) 7190 { 7191 SetClassLongA(hwnd, GCL_STYLE, cl); 7192 } 7193 7194 wclassStyle = cl; 7195 } 7196 } 7197 7198 7199 package abstract class ControlSuperClass: Control // dapi.d 7200 { 7201 // Call previous wndProc(). 7202 abstract protected void prevWndProc(ref Message msg); 7203 7204 7205 protected override void wndProc(ref Message msg) 7206 { 7207 switch(msg.msg) 7208 { 7209 case WM_PAINT: 7210 { 7211 RECT uprect; 7212 //GetUpdateRect(hwnd, &uprect, true); 7213 //onInvalidated(new InvalidateEventArgs(Rect(&uprect))); 7214 7215 //if(!msg.wParam) 7216 GetUpdateRect(hwnd, &uprect, false); // Preserve. 7217 7218 prevWndProc(msg); 7219 7220 // Now fake a normal paint event... 7221 7222 scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd)); 7223 //scope Graphics gpx = new CommonGraphics(hwnd, msg.wParam ? cast(HDC)msg.wParam : GetDC(hwnd), msg.wParam ? false : true); 7224 HRGN hrgn; 7225 7226 hrgn = CreateRectRgnIndirect(&uprect); 7227 SelectClipRgn(gpx.handle, hrgn); 7228 DeleteObject(hrgn); 7229 7230 scope PaintEventArgs pea = new PaintEventArgs(gpx, Rect(&uprect)); 7231 7232 // Can't erase the background now, Windows just painted.. 7233 //if(ps.fErase) 7234 //{ 7235 // prepareDc(gpx.handle); 7236 // onPaintBackground(pea); 7237 //} 7238 7239 prepareDc(gpx.handle); 7240 onPaint(pea); 7241 } 7242 break; 7243 7244 case WM_PRINTCLIENT: 7245 { 7246 prevWndProc(msg); 7247 7248 scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd)); 7249 scope PaintEventArgs pea = new PaintEventArgs(gpx, 7250 Rect(Point(0, 0), wclientsz)); 7251 7252 prepareDc(pea.graphics.handle); 7253 onPaint(pea); 7254 } 7255 break; 7256 7257 case WM_PRINT: 7258 Control.defWndProc(msg); 7259 break; 7260 7261 case WM_ERASEBKGND: 7262 Control.wndProc(msg); 7263 break; 7264 7265 case WM_NCACTIVATE: 7266 case WM_NCCALCSIZE: 7267 case WM_NCCREATE: 7268 case WM_NCPAINT: 7269 prevWndProc(msg); 7270 break; 7271 7272 case WM_KEYDOWN: 7273 case WM_KEYUP: 7274 case WM_CHAR: 7275 case WM_SYSKEYDOWN: 7276 case WM_SYSKEYUP: 7277 case WM_SYSCHAR: 7278 //case WM_IMECHAR: 7279 super.wndProc(msg); 7280 return; 7281 7282 default: 7283 prevWndProc(msg); 7284 super.wndProc(msg); 7285 } 7286 } 7287 7288 7289 override void defWndProc(ref Message m) 7290 { 7291 switch(m.msg) 7292 { 7293 case WM_KEYDOWN: 7294 case WM_KEYUP: 7295 case WM_CHAR: 7296 case WM_SYSKEYDOWN: 7297 case WM_SYSKEYUP: 7298 case WM_SYSCHAR: 7299 //case WM_IMECHAR: // ? 7300 prevWndProc(m); 7301 break; 7302 7303 default: 7304 } 7305 } 7306 7307 7308 protected override void onPaintBackground(PaintEventArgs pea) 7309 { 7310 Message msg; 7311 7312 msg.hWnd = handle; 7313 msg.msg = WM_ERASEBKGND; 7314 msg.wParam = cast(WPARAM)pea.graphics.handle; 7315 7316 prevWndProc(msg); 7317 7318 // Don't paint the background twice. 7319 //super.onPaintBackground(pea); 7320 7321 // Event ? 7322 //paintBackground(this, pea); 7323 } 7324 } 7325 7326 7327 /// 7328 class ScrollableControl: Control // docmain 7329 { 7330 // /// 7331 deprecated void autoScroll(bool byes) // setter 7332 { 7333 if(byes) 7334 cbits |= CBits.ASCROLL; 7335 else 7336 cbits &= ~CBits.ASCROLL; 7337 } 7338 7339 // /// ditto 7340 deprecated bool autoScroll() // getter 7341 { 7342 return (cbits & CBits.ASCROLL) == CBits.ASCROLL; 7343 } 7344 7345 7346 // /// 7347 deprecated final void autoScrollMargin(Size sz) // setter 7348 { 7349 //scrollmargin = sz; 7350 } 7351 7352 // /// ditto 7353 deprecated final Size autoScrollMargin() // getter 7354 { 7355 //return scrollmargin; 7356 return Size(0, 0); 7357 } 7358 7359 7360 // /// 7361 deprecated final void autoScrollMinSize(Size sz) // setter 7362 { 7363 //scrollmin = sz; 7364 } 7365 7366 // /// ditto 7367 deprecated final Size autoScrollMinSize() // getter 7368 { 7369 //return scrollmin; 7370 return Size(0, 0); 7371 } 7372 7373 7374 // /// 7375 deprecated final void autoScrollPosition(Point pt) // setter 7376 { 7377 //autoscrollpos = pt; 7378 } 7379 7380 // /// ditto 7381 deprecated final Point autoScrollPosition() // getter 7382 { 7383 //return autoscrollpos; 7384 return Point(0, 0); 7385 } 7386 7387 7388 /// 7389 final @property Size autoScaleBaseSize() // getter 7390 { 7391 return autossz; 7392 } 7393 7394 /// ditto 7395 final @property void autoScaleBaseSize(Size newSize) // setter 7396 in 7397 { 7398 assert(newSize.width > 0); 7399 assert(newSize.height > 0); 7400 } 7401 body 7402 { 7403 autossz = newSize; 7404 } 7405 7406 7407 /// 7408 final @property void autoScale(bool byes) // setter 7409 { 7410 if(byes) 7411 cbits |= CBits.ASCALE; 7412 else 7413 cbits &= ~CBits.ASCALE; 7414 } 7415 7416 /// ditto 7417 final @property bool autoScale() // getter 7418 { 7419 return (cbits & CBits.ASCALE) == CBits.ASCALE; 7420 } 7421 7422 7423 final @property Point scrollPosition() // getter 7424 { 7425 return Point(xspos, yspos); 7426 } 7427 7428 7429 static Size calcScale(Size area, Size toScale, Size fromScale) // package 7430 in 7431 { 7432 assert(fromScale.width); 7433 assert(fromScale.height); 7434 } 7435 body 7436 { 7437 area.width = cast(int)(cast(float)area.width / cast(float)fromScale.width * cast(float)toScale.width); 7438 area.height = cast(int)(cast(float)area.height / cast(float)fromScale.height * cast(float)toScale.height); 7439 return area; 7440 } 7441 7442 7443 Size calcScale(Size area, Size toScale) // package 7444 { 7445 return calcScale(area, toScale, DEFAULT_SCALE); 7446 } 7447 7448 7449 final void _scale(Size toScale) // package 7450 { 7451 bool first = true; 7452 7453 // Note: doesn't get to-scale for nested scrollable-controls. 7454 void xscale(Control c, Size fromScale) 7455 { 7456 c.suspendLayout(); 7457 7458 if(first) 7459 { 7460 first = false; 7461 c.size = calcScale(c.size, toScale, fromScale); 7462 } 7463 else 7464 { 7465 Point pt; 7466 Size sz; 7467 sz = calcScale(Size(c.left, c.top), toScale, fromScale); 7468 pt = Point(sz.width, sz.height); 7469 sz = calcScale(c.size, toScale, fromScale); 7470 c.bounds = Rect(pt, sz); 7471 } 7472 7473 if(c.hasChildren) 7474 { 7475 ScrollableControl scc; 7476 foreach(Control cc; c.controls) 7477 { 7478 scc = cast(ScrollableControl)cc; 7479 if(scc) 7480 { 7481 if(scc.autoScale) // ? 7482 { 7483 xscale(scc, scc.autoScaleBaseSize); 7484 scc.autoScaleBaseSize = toScale; 7485 } 7486 } 7487 else 7488 { 7489 xscale(cc, fromScale); 7490 } 7491 } 7492 } 7493 7494 //c.resumeLayout(true); 7495 c.resumeLayout(false); // Should still be perfectly proportionate if it was properly laid out before scaling. 7496 } 7497 7498 7499 xscale(this, autoScaleBaseSize); 7500 autoScaleBaseSize = toScale; 7501 } 7502 7503 7504 final void _scale() // package 7505 { 7506 return _scale(getAutoScaleSize()); 7507 } 7508 7509 7510 protected override void onControlAdded(ControlEventArgs ea) 7511 { 7512 super.onControlAdded(ea); 7513 7514 if(created) // ? 7515 if(isHandleCreated) 7516 { 7517 auto sc = cast(ScrollableControl)ea.control; 7518 if(sc) 7519 { 7520 if(sc.autoScale) 7521 sc._scale(); 7522 } 7523 else 7524 { 7525 if(autoScale) 7526 _scale(); 7527 } 7528 } 7529 } 7530 7531 7532 //override final Rect displayRectangle() // getter 7533 override @property Rect displayRectangle() // getter 7534 { 7535 Rect result = clientRectangle; 7536 7537 // Subtract dock padding. 7538 result.x = result.x + dpad.left; 7539 result.width = result.width - dpad.right - dpad.left; 7540 result.y = result.y + dpad.top; 7541 result.height = result.height - dpad.bottom - dpad.top; 7542 7543 // Add scroll width. 7544 if(scrollSize.width > clientSize.width) 7545 result.width = result.width + (scrollSize.width - clientSize.width); 7546 if(scrollSize.height > clientSize.height) 7547 result.height = result.height + (scrollSize.height - clientSize.height); 7548 7549 // Adjust scroll position. 7550 result.location = Point(result.location.x - scrollPosition.x, result.location.y - scrollPosition.y); 7551 7552 return result; 7553 } 7554 7555 7556 /// 7557 final @property void scrollSize(Size sz) // setter 7558 { 7559 scrollsz = sz; 7560 7561 _fixScrollBounds(); // Implies _adjustScrollSize(). 7562 } 7563 7564 /// ditto 7565 final @property Size scrollSize() // getter 7566 { 7567 return scrollsz; 7568 } 7569 7570 7571 /// 7572 class DockPaddingEdges 7573 { 7574 private: 7575 7576 int _left, _top, _right, _bottom; 7577 int _all; 7578 //package void delegate() changed; 7579 7580 7581 final: 7582 7583 void changed() 7584 { 7585 dpadChanged(); 7586 } 7587 7588 7589 public: 7590 7591 /// 7592 @property void all(int x) // setter 7593 { 7594 _bottom = _right = _top = _left = _all = x; 7595 7596 changed(); 7597 } 7598 7599 /// ditto 7600 final @property int all() // getter 7601 { 7602 return _all; 7603 } 7604 7605 /// ditto 7606 @property void left(int x) // setter 7607 { 7608 _left = x; 7609 7610 changed(); 7611 } 7612 7613 /// ditto 7614 @property int left() // getter 7615 { 7616 return _left; 7617 } 7618 7619 /// ditto 7620 @property void top(int x) // setter 7621 { 7622 _top = x; 7623 7624 changed(); 7625 } 7626 7627 /// ditto 7628 @property int top() // getter 7629 { 7630 return _top; 7631 } 7632 7633 /// ditto 7634 @property void right(int x) // setter 7635 { 7636 _right = x; 7637 7638 changed(); 7639 } 7640 7641 /// ditto 7642 @property int right() // getter 7643 { 7644 return _right; 7645 } 7646 7647 /// ditto 7648 @property void bottom(int x) // setter 7649 { 7650 _bottom = x; 7651 7652 changed(); 7653 } 7654 7655 /// ditto 7656 @property int bottom() // getter 7657 { 7658 return _bottom; 7659 } 7660 } 7661 7662 7663 /// 7664 final @property DockPaddingEdges dockPadding() // getter 7665 { 7666 return dpad; 7667 } 7668 7669 7670 deprecated final void setAutoScrollMargin(int x, int y) 7671 { 7672 // 7673 } 7674 7675 7676 this() 7677 { 7678 super(); 7679 _init(); 7680 } 7681 7682 7683 enum DEFAULT_SCALE = Size(5, 13); 7684 7685 /// 7686 final @property void hScroll(bool byes) // setter 7687 { 7688 LONG wl = _style(); 7689 if(byes) 7690 wl |= WS_HSCROLL; 7691 else 7692 wl &= ~WS_HSCROLL; 7693 _style(wl); 7694 7695 if(isHandleCreated) 7696 redrawEntire(); 7697 } 7698 7699 7700 /// ditto 7701 final @property bool hScroll() // getter 7702 { 7703 return (_style() & WS_HSCROLL) != 0; 7704 } 7705 7706 7707 /// 7708 final @property void vScroll(bool byes) // setter 7709 { 7710 LONG wl = _style(); 7711 if(byes) 7712 wl |= WS_VSCROLL; 7713 else 7714 wl &= ~WS_VSCROLL; 7715 _style(wl); 7716 7717 if(isHandleCreated) 7718 redrawEntire(); 7719 } 7720 7721 /// ditto 7722 final @property bool vScroll() // getter 7723 { 7724 return (_style() & WS_VSCROLL) != 0; 7725 } 7726 7727 7728 protected: 7729 7730 7731 /+ 7732 override void onLayout(LayoutEventArgs lea) 7733 { 7734 // ... 7735 super.onLayout(lea); 7736 } 7737 +/ 7738 7739 7740 /+ 7741 override void scaleCore(float width, float height) 7742 { 7743 // Might not want to call super.scaleCore(). 7744 } 7745 +/ 7746 7747 7748 override void wndProc(ref Message m) 7749 { 7750 switch(m.msg) 7751 { 7752 case WM_VSCROLL: 7753 { 7754 SCROLLINFO si = void; 7755 si.cbSize = SCROLLINFO.sizeof; 7756 si.fMask = SIF_ALL; 7757 if(GetScrollInfo(m.hWnd, SB_VERT, &si)) 7758 { 7759 int delta, maxp; 7760 maxp = scrollSize.height - clientSize.height; 7761 switch(LOWORD(m.wParam)) 7762 { 7763 case SB_LINEDOWN: 7764 if(yspos >= maxp) 7765 return; 7766 delta = maxp - yspos; 7767 if(autossz.height < delta) 7768 delta = autossz.height; 7769 break; 7770 case SB_LINEUP: 7771 if(yspos <= 0) 7772 return; 7773 delta = yspos; 7774 if(autossz.height < delta) 7775 delta = autossz.height; 7776 delta = -delta; 7777 break; 7778 case SB_PAGEDOWN: 7779 if(yspos >= maxp) 7780 return; 7781 if(yspos >= maxp) 7782 return; 7783 delta = maxp - yspos; 7784 if(clientSize.height < delta) 7785 delta = clientSize.height; 7786 break; 7787 case SB_PAGEUP: 7788 if(yspos <= 0) 7789 return; 7790 delta = yspos; 7791 if(clientSize.height < delta) 7792 delta = clientSize.height; 7793 delta = -delta; 7794 break; 7795 case SB_THUMBTRACK: 7796 case SB_THUMBPOSITION: 7797 //delta = cast(int)HIWORD(m.wParam) - yspos; // Limited to 16-bits. 7798 delta = si.nTrackPos - yspos; 7799 break; 7800 case SB_BOTTOM: 7801 delta = maxp - yspos; 7802 break; 7803 case SB_TOP: 7804 delta = -yspos; 7805 break; 7806 default: 7807 } 7808 yspos += delta; 7809 SetScrollPos(m.hWnd, SB_VERT, yspos, TRUE); 7810 ScrollWindow(m.hWnd, 0, -delta, null, null); 7811 } 7812 } 7813 break; 7814 7815 case WM_HSCROLL: 7816 { 7817 SCROLLINFO si = void; 7818 si.cbSize = SCROLLINFO.sizeof; 7819 si.fMask = SIF_ALL; 7820 if(GetScrollInfo(m.hWnd, SB_HORZ, &si)) 7821 { 7822 int delta, maxp; 7823 maxp = scrollSize.width - clientSize.width; 7824 switch(LOWORD(m.wParam)) 7825 { 7826 case SB_LINERIGHT: 7827 if(xspos >= maxp) 7828 return; 7829 delta = maxp - xspos; 7830 if(autossz.width < delta) 7831 delta = autossz.width; 7832 break; 7833 case SB_LINELEFT: 7834 if(xspos <= 0) 7835 return; 7836 delta = xspos; 7837 if(autossz.width < delta) 7838 delta = autossz.width; 7839 delta = -delta; 7840 break; 7841 case SB_PAGERIGHT: 7842 if(xspos >= maxp) 7843 return; 7844 if(xspos >= maxp) 7845 return; 7846 delta = maxp - xspos; 7847 if(clientSize.width < delta) 7848 delta = clientSize.width; 7849 break; 7850 case SB_PAGELEFT: 7851 if(xspos <= 0) 7852 return; 7853 delta = xspos; 7854 if(clientSize.width < delta) 7855 delta = clientSize.width; 7856 delta = -delta; 7857 break; 7858 case SB_THUMBTRACK: 7859 case SB_THUMBPOSITION: 7860 //delta = cast(int)HIWORD(m.wParam) - xspos; // Limited to 16-bits. 7861 delta = si.nTrackPos - xspos; 7862 break; 7863 case SB_RIGHT: 7864 delta = maxp - xspos; 7865 break; 7866 case SB_LEFT: 7867 delta = -xspos; 7868 break; 7869 default: 7870 } 7871 xspos += delta; 7872 SetScrollPos(m.hWnd, SB_HORZ, xspos, TRUE); 7873 ScrollWindow(m.hWnd, -delta, 0, null, null); 7874 } 7875 } 7876 break; 7877 7878 default: 7879 } 7880 7881 super.wndProc(m); 7882 } 7883 7884 7885 override void onMouseWheel(MouseEventArgs ea) 7886 { 7887 int maxp = scrollSize.height - clientSize.height; 7888 int delta; 7889 7890 UINT wlines; 7891 if(!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &wlines, 0)) 7892 wlines = 3; 7893 7894 if(ea.delta < 0) 7895 { 7896 if(yspos < maxp) 7897 { 7898 delta = maxp - yspos; 7899 if(autossz.height * wlines < delta) 7900 delta = autossz.height * wlines; 7901 7902 yspos += delta; 7903 SetScrollPos(hwnd, SB_VERT, yspos, TRUE); 7904 ScrollWindow(hwnd, 0, -delta, null, null); 7905 } 7906 } 7907 else 7908 { 7909 if(yspos > 0) 7910 { 7911 delta = yspos; 7912 if(autossz.height * wlines < delta) 7913 delta = autossz.height * wlines; 7914 delta = -delta; 7915 7916 yspos += delta; 7917 SetScrollPos(hwnd, SB_VERT, yspos, TRUE); 7918 ScrollWindow(hwnd, 0, -delta, null, null); 7919 } 7920 } 7921 7922 super.onMouseWheel(ea); 7923 } 7924 7925 7926 override void onHandleCreated(EventArgs ea) 7927 { 7928 xspos = 0; 7929 yspos = 0; 7930 7931 super.onHandleCreated(ea); 7932 7933 //_adjustScrollSize(FALSE); 7934 if(hScroll || vScroll) 7935 { 7936 _adjustScrollSize(FALSE); 7937 recalcEntire(); // Need to recalc frame. 7938 } 7939 } 7940 7941 7942 override void onVisibleChanged(EventArgs ea) 7943 { 7944 if(visible) 7945 _adjustScrollSize(FALSE); 7946 7947 super.onVisibleChanged(ea); 7948 } 7949 7950 7951 private void _fixScrollBounds() 7952 { 7953 if(hScroll || vScroll) 7954 { 7955 int ydiff = 0, xdiff = 0; 7956 7957 if(yspos > scrollSize.height - clientSize.height) 7958 { 7959 ydiff = (clientSize.height + yspos) - scrollSize.height; 7960 yspos -= ydiff; 7961 if(yspos < 0) 7962 { 7963 ydiff += yspos; 7964 yspos = 0; 7965 } 7966 } 7967 7968 if(xspos > scrollSize.width - clientSize.width) 7969 { 7970 xdiff = (clientSize.width + xspos) - scrollSize.width; 7971 xspos -= xdiff; 7972 if(xspos < 0) 7973 { 7974 xdiff += xspos; 7975 xspos = 0; 7976 } 7977 } 7978 7979 if(isHandleCreated) 7980 { 7981 if(xdiff || ydiff) 7982 ScrollWindow(hwnd, xdiff, ydiff, null, null); 7983 7984 _adjustScrollSize(); 7985 } 7986 } 7987 } 7988 7989 7990 override void onResize(EventArgs ea) 7991 { 7992 super.onResize(ea); 7993 7994 _fixScrollBounds(); 7995 } 7996 7997 7998 private: 7999 //Size scrollmargin, scrollmin; 8000 //Point autoscrollpos; 8001 DockPaddingEdges dpad; 8002 Size autossz = DEFAULT_SCALE; 8003 Size scrollsz = Size(0, 0); 8004 int xspos = 0, yspos = 0; 8005 8006 8007 void _init() 8008 { 8009 dpad = new DockPaddingEdges; 8010 //dpad.changed = &dpadChanged; 8011 } 8012 8013 8014 void dpadChanged() 8015 { 8016 alayout(this); 8017 } 8018 8019 8020 void _adjustScrollSize(BOOL fRedraw = TRUE) 8021 { 8022 assert(isHandleCreated); 8023 8024 if(!hScroll && !vScroll) 8025 return; 8026 8027 SCROLLINFO si; 8028 //if(vScroll) 8029 { 8030 si.cbSize = SCROLLINFO.sizeof; 8031 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; 8032 si.nPos = yspos; 8033 si.nMin = 0; 8034 si.nMax = clientSize.height; 8035 si.nPage = clientSize.height; 8036 if(scrollSize.height > clientSize.height) 8037 si.nMax = scrollSize.height; 8038 if(si.nMax) 8039 si.nMax--; 8040 SetScrollInfo(hwnd, SB_VERT, &si, fRedraw); 8041 } 8042 //if(hScroll) 8043 { 8044 si.cbSize = SCROLLINFO.sizeof; 8045 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; 8046 si.nPos = xspos; 8047 si.nMin = 0; 8048 si.nMax = clientSize.width; 8049 si.nPage = clientSize.width; 8050 if(scrollSize.width > clientSize.width) 8051 si.nMax = scrollSize.width; 8052 if(si.nMax) 8053 si.nMax--; 8054 SetScrollInfo(hwnd, SB_HORZ, &si, fRedraw); 8055 } 8056 } 8057 } 8058 8059 8060 /// 8061 interface IContainerControl // docmain 8062 { 8063 /// 8064 @property Control activeControl(); // getter 8065 8066 deprecated void activeControl(Control); // setter 8067 8068 deprecated bool activateControl(Control); 8069 } 8070 8071 8072 /// 8073 class ContainerControl: ScrollableControl, IContainerControl // docmain 8074 { 8075 /// 8076 @property Control activeControl() // getter 8077 { 8078 /+ 8079 HWND hwfocus, hw; 8080 hw = hwfocus = GetFocus(); 8081 while(hw) 8082 { 8083 if(hw == this.hwnd) 8084 return Control.fromChildHandle(hwfocus); 8085 hw = GetParent(hw); 8086 } 8087 return null; 8088 +/ 8089 Control ctrlfocus, ctrl; 8090 ctrl = ctrlfocus = Control.fromChildHandle(GetFocus()); 8091 while(ctrl) 8092 { 8093 if(ctrl is this) 8094 return ctrlfocus; 8095 ctrl = ctrl.parent; 8096 } 8097 return null; 8098 } 8099 8100 /// ditto 8101 @property void activeControl(Control ctrl) // setter 8102 { 8103 if(!activateControl(ctrl)) 8104 throw new DflException("Unable to activate control"); 8105 } 8106 8107 8108 /// 8109 // Returns true if successfully activated. 8110 final bool activateControl(Control ctrl) 8111 { 8112 // Not sure if this is correct. 8113 8114 if(!ctrl.canSelect) 8115 return false; 8116 //if(!SetActiveWindow(ctrl.handle)) 8117 // return false; 8118 ctrl.select(); 8119 return true; 8120 } 8121 8122 8123 /// 8124 final @property Form parentForm() // getter 8125 { 8126 Control par; 8127 Form f; 8128 8129 for(par = parent; par; par = par.parent) 8130 { 8131 f = cast(Form)par; 8132 if(f) 8133 return f; 8134 } 8135 8136 return null; 8137 } 8138 8139 8140 /+ 8141 final bool validate() 8142 { 8143 // ... 8144 } 8145 +/ 8146 8147 8148 this() 8149 { 8150 super(); 8151 _init(); 8152 } 8153 8154 8155 /+ 8156 // Used internally. 8157 this(HWND hwnd) 8158 { 8159 super(hwnd); 8160 _init(); 8161 } 8162 +/ 8163 8164 8165 private void _init() 8166 { 8167 //wexstyle |= WS_EX_CONTROLPARENT; 8168 ctrlStyle |= ControlStyles.CONTAINER_CONTROL; 8169 } 8170 8171 8172 protected: 8173 /+ 8174 override bool processDialogChar(char charCode) 8175 { 8176 // Not sure if this is correct. 8177 return false; 8178 } 8179 +/ 8180 8181 8182 /+ 8183 deprecated protected override bool processMnemonic(dchar charCode) 8184 { 8185 return false; 8186 } 8187 8188 8189 bool processTabKey(bool forward) 8190 { 8191 if(isHandleCreated) 8192 { 8193 //SendMessageA(hwnd, WM_NEXTDLGCTL, !forward, 0); 8194 //return true; 8195 select(true, forward); 8196 } 8197 return false; 8198 } 8199 +/ 8200 } 8201 8202 8203 import std.traits, std.typecons; 8204 private template hasLocalAliasing(T...) 8205 { 8206 static if( !T.length ) 8207 enum hasLocalAliasing = false; 8208 else 8209 enum hasLocalAliasing = std.traits.hasLocalAliasing!(T[0]) || 8210 dfl.control.hasLocalAliasing!(T[1 .. $]); 8211 } 8212 8213 /// 8214 shared class SharedControl 8215 { 8216 private: 8217 Control _ctrl; 8218 8219 LPARAM makeParam(ARGS...)(void function(Control, ARGS) fn, Tuple!(ARGS)* args) 8220 if (ARGS.length) 8221 { 8222 static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof); 8223 static struct InvokeParam 8224 { 8225 void function(Control, ARGS) fn; 8226 ARGS args; 8227 } 8228 alias dfl.internal.clib.malloc malloc; 8229 alias dfl.internal.clib.free free; 8230 8231 auto param = cast(InvokeParam*)malloc(InvokeParam.sizeof); 8232 param.fn = fn; 8233 param.args = args.field; 8234 8235 if (!param) 8236 throw new OomException(); 8237 8238 auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof); 8239 8240 if (!p) 8241 throw new OomException(); 8242 8243 8244 static void fnentry(Control c, size_t[] p) 8245 { 8246 auto param = cast(InvokeParam*)p[0]; 8247 param.fn(c, param.args); 8248 free(param); 8249 } 8250 8251 p.fp = &fnentry; 8252 p.nparams = 1; 8253 p.params[0] = cast(size_t)param; 8254 8255 return cast(LPARAM)p; 8256 } 8257 8258 8259 LPARAM makeParamNoneArgs(void function(Control) fn) 8260 { 8261 static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof); 8262 alias dfl.internal.clib.malloc malloc; 8263 alias dfl.internal.clib.free free; 8264 8265 auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof); 8266 8267 if (!p) 8268 throw new OomException(); 8269 8270 static void fnentry(Control c, size_t[] p) 8271 { 8272 auto fn = cast(void function(Control))p[0]; 8273 fn(c); 8274 } 8275 8276 p.fp = &fnentry; 8277 p.nparams = 1; 8278 p.params[0] = cast(size_t)fn; 8279 8280 return cast(LPARAM)p; 8281 } 8282 8283 8284 8285 public: 8286 /// 8287 this(Control ctrl) 8288 { 8289 assert(ctrl); 8290 _ctrl = cast(shared)ctrl; 8291 } 8292 8293 /// 8294 void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) 8295 if (ARGS.length && !hasLocalAliasing!(ARGS)) 8296 { 8297 auto ctrl = cast(Control)_ctrl; 8298 auto hwnd = ctrl.handle; 8299 8300 if(!hwnd) 8301 Control.badInvokeHandle(); 8302 8303 auto t = tuple(args); 8304 auto p = makeParam(fn, &t); 8305 SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p); 8306 } 8307 8308 /// 8309 void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) 8310 if (!ARGS.length) 8311 { 8312 auto ctrl = cast(Control)_ctrl; 8313 auto hwnd = ctrl.handle; 8314 8315 if(!hwnd) 8316 Control.badInvokeHandle(); 8317 8318 auto p = makeParamNoneArgs(fn); 8319 SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p); 8320 } 8321 8322 /// 8323 void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) 8324 if (ARGS.length && !hasLocalAliasing!(ARGS)) 8325 { 8326 auto ctrl = cast(Control)_ctrl; 8327 auto hwnd = ctrl.handle; 8328 8329 if(!hwnd) 8330 Control.badInvokeHandle(); 8331 8332 auto t = tuple(args); 8333 auto p = makeParam(fn, &t); 8334 PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p); 8335 } 8336 8337 /// 8338 void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) 8339 if (!ARGS.length) 8340 { 8341 auto ctrl = cast(Control)_ctrl; 8342 auto hwnd = ctrl.handle; 8343 8344 if(!hwnd) 8345 Control.badInvokeHandle(); 8346 8347 auto p = makeParamNoneArgs(fn); 8348 PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p); 8349 } 8350 }