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