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